Description
有一家公司有N个员工(从1到N),公司里每个员工都有一个直接的老板(除了整个公司的领导)。如果你是某人的直接老板,那个人就是你的下属,他的所有下属也都是你的下属。如果你是没有人的老板,那么你就没有下属,没有直接老板的员工就是整个公司的领导,也就是说N个员工构成了一棵树。公司通常把一些任务分配给一些员工来完成,当一项任务分配给某个人时,他/她会把它分配给他/她的所有下属,换句话说,这个人和他/她的所有下属在同一时间接受了一项任务。此外,每当员工收到一个任务,他/她将停止当前任务(如果他/她有),并开始新的任务。在公司将某些任务分配给某个员工后,编写一个程序来帮助找出某个员工当前的任务。
Input
第一行包含单个正整数T(T<=10),表示测试用例的数量。对于每个测试用例:第一行包含一个整数N(N≤50,000),它是雇员的数目。下面的N-1行分别包含两个整数u和v,这意味着雇员v是雇员u的直接老板(1<=u,v<=N)。下一行包含一个整数M(M≤50,000)。下面的M行分别包含一条消息,“Cx”表示对员工x的当前任务的查询,“Tx y”表示公司将任务y分配给员工x。(1<=x<=N,0<=y<=10^9)
Output
对于每个测试用例,在第一行打印测试用例编号(以1开头),然后为每个查询输出相应的答案。
Sample Input
1 5 4 3 3 2 1 3 5 2 5 C 3 T 2 1 C 3 T 3 2 C 3Sample Output
Case #1: -1 1 2
题解:
经典的线段树维护dfs序的题目,这个题只要知道dfs序就能简化成一道简单的区间染色加单点查询问题。
首先了解一下dfs序,其实就是对一棵树进行dfs时的入栈和出栈序列,拿一个经典的例子来讲吧。
这一棵树的dfs序就是
很容易发现一个节点的子孙节点一定在他的入栈和出栈的时间序列之内,因此我们就把一颗非线性的树状结构转换成了线性结构,那么这个题就很好做了,我们求出每个节点的入栈和出栈的时间序列(就是区间,可以用一个时间戳来记录)。
求dfs序的代码实现如下:
void dfs(int x){ ll[x]=index++; for(int i=0;i<G[x].size();i++) dfs(G[x][i]); rr[x]=index++; }
然后就很简单了。
对应操作:T 2 1 就是把2节点的dfs序之后的区间染成1,对应区间修改
C 2 就是查询2节点的颜色,对应单点查询
代码(线段树)
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define e 2.718281828 #define rp(i,s,t) for (i = (s); i <= (t); i++) #define RP(i,s,t) for (i = (t); i >= (s); i--) // #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } const int N = 1e5+7; vector<int> G[N]; int visited[N],ll[N],rr[N]; int index; struct node{ int l,r; int color; }tree[N<<2]; void pushdown(int rt){ tree[rt<<1].color=tree[rt<<1|1].color=tree[rt].color; tree[rt].color=-1; } void build(int l,int r,int rt){ tree[rt].l=l,tree[rt].r=r; tree[rt].color=-1; if(l==r) return ; int m=(l+r)>>1; build(lson); build(rson); } void update(int L,int R,int val,int l,int r,int rt){ if(L<=l&&r<=R){ tree[rt].color=val; return ; } if(tree[rt].color!=-1) pushdown(rt); int m=(l+r)>>1; if(L<=m) update(L,R,val,lson); if(m<R) update(L,R,val,rson); } int query(int pos,int l,int r,int rt){ if(tree[rt].l==tree[rt].r){ return tree[rt].color; } if(tree[rt].color!=-1) pushdown(rt); int m=(l+r)>>1; if(pos<=m) query(pos,lson); else query(pos,rson); } void dfs(int x){ ll[x]=index++; for(int i=0;i<G[x].size();i++) dfs(G[x][i]); rr[x]=index++; } int main(){ int T=read(); int c=0; while(T--){ printf("Case #%d:\n",++c); int n=read(),i; build(1,2*n,1); mst(ll,-1); mst(rr,-1); rp(i,1,n) visited[i]=0,G[i].clear(); rp(i,1,n-1){ int x=read(),y=read(); G[y].push_back(x); visited[x]=1; } index=1; rp(i,1,n) if(!visited[i]) dfs(i); int m=read(); while(m--){ char opt[10]; scanf("%s",opt); if(opt[0]=='T') { int x=read(),y=read(); update(ll[x],rr[x],y,1,2*n,1); } else if(opt[0]=='C'){ int x=read(); printf("%d\n",query(ll[x],1,2*n,1)); } } // printf("\n"); } return 0; }
当然对于这个题而言,因为给的数据比较水,因此我们可以直接暴力,当然这样没什么意义。
这种解法就是直接模拟建一棵树,然后再暴力修改所有子孙节点,其实可以出一组50000的数据,就是一颗50000叉树,
就可以成功把这种做法给hack掉,还是给代码吧
暴力的代码实现
#include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define e 2.718281828 #define rp(i,s,t) for (i = (s); i <= (t); i++) #define RP(i,s,t) for (i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } const int N = 5e4+7; int w[N]; int main(){ int T=read(); int c=0; while(T--){ printf("Case #%d:\n",++c); int n=read(),i; vector<int> ve[n+5]; mst(w,-1); rp(i,1,n-1){ int x=read(),y=read(); ve[y].push_back(x); } int m=read(); while(m--){ char opt[10]; scanf("%s",opt); if(opt[0]=='T') { int a=read(),b=read(); queue<int>link; link.push(a); while(!link.empty()){ a=link.front(); link.pop(); w[a]=b; for(int i=0;i<ve[a].size();i++) link.push(ve[a][i]); } } else if(opt[0]=='C'){ int x=read(); printf("%d\n",w[x]); } } // printf("\n"); } return 0; }