第五周训练 | 二叉树+线段树
A - Binary Tree Traversals
记一个模板
#include<iostream> using namespace std; typedef struct Tree{ Tree *left; Tree *right; int value; }Tree; Tree *root; Tree* create(int *preorder,int *inorder,int n) { Tree *temp; for(int i=0;i<n;i++) { if(preorder[0]==inorder[i]) { temp=(Tree*)malloc(sizeof(Tree)); temp->value=inorder[i]; temp->left=create(preorder+1,inorder,i); temp->right=create(preorder+i+1,inorder+i+1,n-i-1); return temp; } } return NULL; } void postOrder(Tree *postTree) { if(postTree!=NULL) { postOrder(postTree->left); postOrder(postTree->right); if(postTree==root) printf("%d\n",postTree->value); else printf("%d ",postTree->value); } } int main() { int n; int preorder[2010],inorder[2010]; while(scanf("%d",&n)!=EOF) { root=NULL; for(int i=0;i<n;i++) scanf("%d",&preorder[i]); for(int i=0;i<n;i++) scanf("%d",&inorder[i]); root=create(preorder,inorder,n); postOrder(root); } return 0; }
B - The order of a Tree
bst树的创建,虽然不知道它有什么用。。。
创建的时候每一次都是从根【总根】开始判断
#include<iostream>
#include<set>
#define N 100001
using namespace std;
set<int>order;
int k,ii;
int n;
struct node
{
node* l;
node* r;
int date;
node(int date,node *l=NULL,node *r=NULL):date(date),l(l),r(r){}
};
void create(node* &root,int val)
{
if(!root)
{
root =new node(val);
}
else if(val<root->date)
{
create(root->l,val);
}
else
{
create(root->r,val);
}
}
void preorder(node *root)
{
if(root)
{
printf("%d%c",root->date,ii==n-1 ? '\n':' ');
++ii;
preorder(root->l);
preorder(root->r);
}
}
int main()
{
node *root;
root=NULL;
cin>>n;
int temp;
for(int i=0;i<n;++i)
{
scanf("%d",&temp);
create(root,temp);
}
preorder(root);
return 0;
}
C - 二叉搜索树
#include<iostream> #include<cstring> using namespace std; #define MAX 200 char tree1[MAX],tree2[MAX],n; string s; void create_tree(char tree[],char node) { int root=1; while(tree[root]!='\0') { if(node < tree[root]) { root*=2; } else { root*=2; root++; } } tree[root] = node; } int main() { while(scanf("%d",&n)&&n) { cin>>s; memset(tree1,0,sizeof(tree1)); for(int i=0;i<s.length();++i)create_tree(tree1,s[i]); for(int i=0;i<n;++i) { cin>>s; memset(tree2,0,sizeof(tree2)); for(int i=0;i<s.length();++i) create_tree(tree2,s[i]); if(memcmp(tree1,tree2,sizeof(tree1))==0) cout<<"YES\n"; else cout<<"NO\n"; } } return 0; }
D - Hardwood Species
#include<iostream> #include<cstring> #include<map> #include<stdio.h> using namespace std; #define MAX 200 string s; int main() { map<string,int>mp; int num=0; while(getline(cin,s)!=NULL){ mp[s]++;num++; } map<string,int>::iterator i; for(i=mp.begin();i!=mp.end();++i) { cout<<i->first;printf(" %.4f\n",i->second*100.0/num); } return 0; }
E - Lost Cows
#include<iostream> #include<cstdio> /** 二叉查找树:(又:二叉搜索树,二叉排序树) 它或者是一棵空树,或者是二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 线段树: 是一种二叉搜索树,与区间树相似, 它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点 分析: 剩下的数中 有n个数比他小,那么这个数的值是【拿去后的数中】n+1 */ using namespace std; const int maxn=10000; int small[maxn],ans[maxn]; struct node{ int lc,rc,len; }; node tree[maxn*3];//这里一开始数组开小了出现了rte void build(int x,int lc,int rc)//构造一棵线段树 { tree[x].lc=lc,tree[x].rc=rc;//记录区间的端点值 tree[x].len=rc-lc+1;//记录区间长 if(lc==rc)return ; build(x*2,lc,(lc+rc)/2);//构造左子树 build(x*2+1,(lc+rc)/2+1,rc);//构造右子树 } int query(int base,int k) { tree[base].len--;//代表有数被拿走,这个区间的长度自减 if(tree[base].lc==tree[base].rc)return tree[base].lc;//当左右子树的端点值一样的时候戴白哦达到了叶子 if(k<=tree[base*2].len)// 区间的长度代表了数的个数 { return query(base*2,k);//左边 } else { return query(base*2+1,k-tree[base*2].len);//右边 } } int main(void) { int n; scanf("%d",&n); small[1]=0; for(int i=2;i<=n;i++)//输入数据 { scanf("%d",&small[i]); } build(1,1,n);//建线段树 1-n从小到大 for(int i=n;i>=1;i--)//从后往前找 { ans[i]=query(1,small[i]+1);//从根开始,找区间长度为的small[i]+1 } for(int i=1;i<=n;i++) { printf("%d\n",ans[i]); } return 0; }
F - Mayor's posters
POJ - 2528[lazy]
#include<algorithm> #include<iostream> #include<cstring> #include<string> #include<cstdio> #include<vector> #include<stack> #include<cmath> #include<queue> #include<set> #include<map> #define md(l,r) (l+r)>>1 #define rson(x) x<<1|1 #define lson(x) x<<1 #define endl '\n' #define sc(x) scanf("%d",&x) using namespace std; typedef long long LL; const int inf=0x3f3f3f3f; const int size=1e5+5; int Ledge[size],Redge[size];//放端点的 int lid[size],rid[size]; vector<int > V; typedef long long LL; struct node { int l,r; LL sum; LL tag; } tree[size<<2]; void build(int k,int l,int r) { tree[k].l=l,tree[k].r=r; if(l==r) { tree[k].sum=0; return ; } int mid(md(l,r)); build(lson(k),l,mid); build(rson(k),mid+1,r); } void change(int k) { if(tree[k].l!=tree[k].r) { int ls=lson(k),rs=rson(k); tree[ls].sum=tree[k].tag; tree[rs].sum=tree[k].tag; tree[ls].tag=tree[k].tag; tree[rs].tag=tree[k].tag; } tree[k].tag=0; } void Print() { for(int i=0;i<20;++i) { cout<<i<<":"<<tree[i].l<<","<<tree[i].r<<","<<tree[i].sum<<","<<tree[i].tag<<endl; } } int query(int k,int l,int r) { LL ans=inf; if(tree[k].tag) change(k);//如果已经被染过色了,端点染色然后初始化 if(tree[k].l==l&&tree[k].r==r) { return tree[k].sum; } int mid=md(tree[k].l,tree[k].r); if(r<=mid) ans=query(lson(k),l,r);//小区间在左边 else if(l>=mid+1) ans=query(rson(k),l,r);//小区间在右边 else ans=min(query(lson(k),l,mid),query(rson(k),mid+1,r));//mid在小区间内就把小区间分割 return ans; } void add(int k,int l,int r,LL x) { if(tree[k].tag) change(k);//端点染色判断 if(tree[k].l==l&&tree[k].r==r) { tree[k].sum=x;//区间内部涂色 tree[k].tag=x;//tag用来记录这个区间属于哪个小区间 return ; } int mid=md(tree[k].l,tree[k].r); if(l>=mid+1) add(rson(k),l,r,x); else if(r<=mid) add(lson(k),l,r,x); else add(lson(k),l,mid,x),add(rson(k),mid+1,r,x); tree[k].sum=min(tree[lson(k)].sum,tree[rson(k)].sum);//从左右端点选着那个小的作为这个区间的颜色 } int main() { int t;sc(t); int ans=0; while(t--) { int n; ans=0; V.clear(); memset(tree,0,sizeof(tree)); sc(n); for(int i=0; i<n; i++) { sc(Ledge[i]),sc(Redge[i]);//输入左右端点 V.push_back(Ledge[i]),V.push_back(Redge[i]); } sort(V.begin(),V.end());//建立数组 V.erase(unique(V.begin(),V.end()),V.end());//离散化——建新的数组 /* iterator erase( iterator _First, iterator _Last); 删除从_First开始到_Last位置(不包括_Last位置)的元素 返回值也是一个迭代器,指向最后一个删除元素的下一个位置。 unique函数的功能:”删除”序列中所有相邻的重复元素(只保留一个)。 此处的删除,并不是真的删除,而是指重复元素的位置被不重复的元素给占领了 */ for(int i=0; i<n; i++) lid[i]=lower_bound(V.begin(),V.end(),Ledge[i])-V.begin()+1; //离散化——绑定新的区间 for(int i=0; i<n; i++) rid[i]=lower_bound(V.begin(),V.end(),Redge[i])-V.begin()+1; /* lower_bound():int t=lower_bound(a+l,a+r,m)-a 在升序排列的a数组内二分查找[l,r)区间内的值为m的元素。 返回m在数组中的下标 */ build(1,1,V.size()+1);//建线段树 for(int i=n-1; i>=0; i--) //倒着来 { if(query(1,lid[i],rid[i])==0) //传入一个区间和根 { add(1,lid[i],rid[i],i); ans++; } } cout<<ans<<endl; } return 0; }
G - A Simple Problem with Integers
POJ - 3468 [lazy]
#include<iostream> #include<stdio.h> using namespace std; typedef long long ll ; const int N=1e5+10; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct Node { int l,r; int mid() { return (l+r)>>1; } }tree[N<<2]; ll sum[N<<2],add[N<<2]; void PushUp(int rt) { sum[rt] = sum[rt<<1]+sum[rt<<1|1]; } void PushDown(int rt,int m) { if(add[rt]) { add[rt<<1]+=add[rt];//左右节点添加延迟修改量,有可能有多个延迟修改量,这里用+= add[rt<<1|1]+=add[rt]; sum[rt<<1]+=add[rt]*(m-(m>>1)); sum[rt<<1|1]+=add[rt]*(m>>1); add[rt]=0; } } void build(int l,int r,int rt) { tree[rt].l=l; tree[rt].r=r; add[rt]=0; if(l==r) { scanf("%I64d",&sum[rt]);return; } int m=tree[rt].mid(); build(lson) ; build(rson) ; PushUp(rt); } void update(int c,int l,int r,int rt) { if(tree[rt].l==l&&tree[rt].r==r) { add[rt]+=c;//给父节点打上一个lazy标签,子节点看情况修改 sum[rt]+=(ll)c*(r-l+1); return; } if(tree[rt].l==tree[rt].r) return; PushDown( rt , tree[rt].r - tree[rt].l + 1); int m=tree[rt].mid(); if(r<=m) update(c,l,r,rt<<1); else if(l>m) update(c,l,r,rt<<1|1); else { update(c,lson); update(c,rson); } PushUp(rt); } ll query(int l,int r,int rt) { if(l==tree[rt].l&&r==tree[rt].r) return sum[rt]; PushDown(rt,tree[rt].r-tree[rt].l+1);//一层 int m=tree[rt].mid(); ll res = 0; if(r<=m) res+=query(l,r,rt<<1); else if(l>m) res+=query(l,r,rt<<1|1); else { res+=query(lson); res+=query(rson); } return res; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { build(1,n,1); while(m--) { char ch[2]; scanf("%s",ch); int a,b,c; if(ch[0]=='Q') { scanf("%d%d",&a,&b); printf("%lld\n",query(a,b,1)); } else { scanf("%d%d%d",&a,&b,&c); update(c,a,b,1); } } } return 0; }
H - 敌兵布阵
#include<iostream> #include<cstring> #include<stdio.h> using namespace std; typedef long long ll ; const int N=1e5+10; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct Node { int l,r; int mid() { return (l+r)>>1; } }tree[N<<2]; ll sum[N<<2],add[N<<2]; void PushUp(int rt) { sum[rt] = sum[rt<<1]+sum[rt<<1|1]; } void Init() { memset(sum,0,sizeof(N<<2)); memset(add,0,sizeof(N<<2)); memset(tree,0,sizeof(N<<2)); } void build(int l,int r,int rt) { tree[rt].l=l;tree[rt].r=r; if(l==r) { scanf("%I64d",&sum[rt]);return; } int m=tree[rt].mid(); build(lson) ; build(rson) ; PushUp(rt); } void update(int c,int l,int r,int rt) { if(tree[rt].r==tree[rt].l) { sum[rt]+=c; return; } int m=tree[rt].mid(); if(r<=m) update(c,l,r,rt<<1); else if(l>m) update(c,l,r,rt<<1|1); else { update(c,lson); update(c,rson); } PushUp(rt); } ll query(int l,int r,int rt) { if(l==tree[rt].l&&r==tree[rt].r) return sum[rt]; int m=tree[rt].mid();ll res = 0; if(r<=m) res+=query(l,r,rt<<1); else if(l>m) res+=query(l,r,rt<<1|1); else { res+=query(lson); res+=query(rson); } return res; } int main() { int T,N;scanf("%d",&T); for(int i=1;i<=T;++i) { scanf("%d",&N);build(1,N,1); string ch; int a,b,c; printf("Case %d:\n",i); do { cin>>ch; if(ch=="Query") { scanf("%d%d",&a,&b); printf("%lld\n",query(a,b,1)); } else if(ch=="Add") { scanf("%d%d",&a,&b); update(b,a,a,1); } else if(ch=="Sub") { scanf("%d%d",&a,&b); update(-b,a,a,1); } }while(ch!="End"); Init(); } return 0; }
I - Minimum Inversion Number
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; #define maxn 5555 #define inf 99999999 int a[maxn]; struct node{ int l,r,sum;//sum记录区间长 }tree[maxn*4]; int ans=0; void pushup(int v) { tree[v].sum=tree[v<<1].sum+tree[v<<1|1].sum; } void build(int l,int r,int v) { tree[v].l=l;tree[v].r=r;tree[v].sum=0; if(l==r) return; int mid=(l+r)/2; build(l,mid,v<<1); build(mid+1,r,v<<1|1); } int query(int l,int r,int v)//求区间长度 { if(l==tree[v].l&&r==tree[v].r) return tree[v].sum; int mid=(tree[v].l+tree[v].r)/2; if(r<=mid) return query(l,r,v<<1); else if(l>mid) return query(l,r,v<<1|1); else { return query(l,mid,v<<1)+query(mid+1,r,v<<1|1); } } void update(int pos,int v)//更新区间长度 { if(tree[v].l==tree[v].r){ tree[v].sum=1;return ; } int mid=(tree[v].l+tree[v].r)/2; if(pos<=mid) update(pos,v<<1); else update(pos,v<<1|1); pushup(v); } int main() { int n; while(~scanf("%d",&n)) { memset(a,0,sizeof(a)); for(int i=0;i<n;i++) scanf("%d",&a[i]); build(0,n-1,1); int sum=0,min1=inf; for(int i=0;i<n;i++) { ans=query(a[i],n-1,1);//计算a[i]对应的逆序数个数 =大于它的且已经出现过的数的个数 sum+=ans; update(a[i],1);//将a[i]标记到数列中 } for(int i=0;i<n;i++) { sum+=n-(a[i]+1)-a[i]; if(sum<min1) min1=sum; } printf("%d\n",min1); } }
J - Just a Hook