Byteland国家的网络单向传输系统可以被看成是以首都Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的。现在他们开始在其他城市陆续建立了新的基站,命令“C x“代表在城市x建立了一个新的基站,不会在同一个城市建立多个基站;城市编号为1到n,其中城市1就是首都Bytetown。在建立基站的过程中他们还会询问某个城市的网络信号是从哪个城市传输过来的,命令”Q x“代表查询城市x的来源城市。
标签:
Byteland国家的网络单向传输系统可以被看成是以首都Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的。现在他们开始在其他城市陆续建立了新的基站,命令“C x“代表在城市x建立了一个新的基站,不会在同一个城市建立多个基站;城市编号为1到n,其中城市1就是首都Bytetown。在建立基站的过程中他们还会询问某个城市的网络信号是从哪个城市传输过来的,命令”Q x“代表查询城市x的来源城市。
输入有多组测试数据。每组数据的第一行包含两个正整数n和m(1 <= n,m <= 100,000),分别代表城市数和命令数。接下来n-1行,每行两个正整数u和v,代表一条从城市u到城市v的网络传输通道。之后的m行,每行一个命令”C x“或”Q x”。
所有输入的n和m的总和分别都不超过500,000,两组输入数据之间用一个空行隔开。
对于每个查询命令,输出一个整数y,表示来源城市。每两组数据之间用一个空格隔开。
3 4 1 2 2 3 Q 3 C 2 Q 2 Q 3
1 2 2
题目大意:给定一个关系树,有两种操作,一个是询问这个关系树的根节点,一个是将这个关系树分割。
可以使用并查集,由于关系树可能退化成一条链,每次查询时可能会查询整个链,考虑路径压缩,然而后面可能会有c操作,
对于这种问题,一大堆的询问操作和分割操作,相互交叉,类似于之前做过的一道题,求一段区间中相异数之和,全部读入查询操作,
进行编号,然后依次回答以结尾的查询操作,再根据编号回答,离线操作就是映射了一遍,这道题假设读入所有的c操作,建立一棵
终极树,貌似不能回答没有进行c操作之前的查询,不可能吗?
我们可以倒着做,回答最后一个c之后的查询,然后将这棵树还原到c之前的状态,再次回答,以此类推,将树的状态还原到初始状态,
对每一个状态我们都可以进行带有路压缩的查询了,降低了时间复杂度。
#include <iostream> #include <cstdio> #include <string> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; #define maxn 110000 int n,m; int q[maxn],c[maxn]; //c数组存的是从开始到结束基站的编号 int father[maxn]; //基站之前的信号发射点 int uset[maxn]; int Rank[maxn]; int answer[maxn]; //从末尾到起始的Q的答案 vector < int > G[maxn]; int cnum; int MM; void init() { cnum=0; MM=0; memset(q,0,sizeof(q)); memset(c,0,sizeof(c)); memset(father,0,sizeof(father)); memset(answer,0,sizeof(answer)); for(int i=0;i<maxn;i++) G[i].clear(); } void MakeSet() { for(int i=1;i<=n;i++) { uset[i]=i; Rank[i]=0; } } int Find1(int x) { if(x!=uset[x]) Find1(uset[x]); return uset[x]; } void unionSet(int x,int y) { int fx=Find1(x); int fy=Find1(y); if(fx!=fy) { if(Rank[fx]>Rank[fy]) uset[fy]=fx; if(Rank[fx]<Rank[fy]) uset[fx]=fy; if(Rank[fx]==Rank[fy]) { uset[fx]=fy; Rank[fx]++; } } } int Find2(int x) { if(x!=uset[x]) uset[x]=Find2(uset[x]); return uset[x]; } void input() { for(int i=1;i<=n-1;i++) { int fa,son; scanf("%d%d",&fa,&son); uset[son]=fa; } for(int i=1;i<=m;i++) { char s[10]; int num; scanf("%s",s); if(s[0]==‘Q‘) { scanf("%d",&num); G[cnum].push_back(num); } if(s[0]==‘C‘) { scanf("%d",&num); G[++cnum].push_back(num); c[cnum]=num; father[num]=Find1(uset[num]); uset[num]=num; //分割开 } } /*cout<<"cnum "<<cnum<<endl; for(int i=cnum;i>=0;i--) { printf("%d ",G[i].size()); for(int j=G[i].size()-1;j>=0;j--) { printf("%d ",G[i][j]); } printf("\n"); }*/ } void solve() { // cout<<"cnum "<<cnum<<endl; for(int i=cnum;i>=0;i--) { if(i==0) { /*for(int j=G[i].size()-1;j>=1;j--) { printf("%d ",G[i][j]); } cout<<endl;*/ // cout<<"0 "<<G[i].size()<<endl;00 for(int j=G[i].size()-1;j>=0;j--) { int x=G[i][j]; answer[MM++]=Find2(x); // cout<<"0 "<<G[i][j]<<" "<<answer[MM-1]<<endl; } } else { /* for(int j=G[i].size()-1;j>=1;j--) { printf("%d ",G[i][j]); } cout<<endl;*/ for(int j=G[i].size()-1;j>=1;j--) { int x=G[i][j]; answer[MM++]=Find2(x); // cout<<"1 "<<answer[MM-1]<<endl; } // cout<<"G[i][0] "<<G[i][0]<<endl; // cout<<"father[G[i][0]] "<<father[G[i][0]]<<endl; uset[G[i][0]]=father[G[i][0]]; } } for(int i=MM-1;i>=0;i--) printf("%d\n",answer[i]); } int main() { while(~scanf("%d%d",&n,&m)) { init(); MakeSet(); input(); solve(); } return 0; }
snnu(1110) 传输网络 (并查集+路径压缩+离线操作)
标签:
原文地址:http://www.cnblogs.com/xianbin7/p/4680634.html