一道题意很复杂的题目,为了表达一句话的意思,用了四句话去描述,纯粹为了误导。
大致题意:一棵树,每个结点i会有一个权值weighti,初始时只有一个权值为0的根节点1。给定Q(Q≤4*105)个操作,操作分两类:
1.1 p q,表示新建结点cnt+1,权值为q,该结点与p结点连边。
2.2 p q,表示求最长的序列P,满足P1=p,对i>1,都有:Pi是Pi-1与根结点路径上离Pi-1最近的权值不小于weighti的点,且所有weightPi加起来(有点拗口,看不懂的可以看原题描述)
具体有一些区别:其实就是强制在线辣,请以实际描述为准。
分析:很明显能看出一些不变的东西:结点只增不减,而后续结点的加入不会影响之前结点的性质,也就是说,一个结点的信息在他加入的时候就已经完全确定,而这些信息都能由祖先的信息推出,于是想到倍增。具体维护两个信息st_par和st_sum(我代码里省事把st_par简写为st,st_sum简写为sum),其中st_par[i][j]表示从结点i向上“跳”2j步的结点编号,这里“跳”一步指的是进行一次寻找“到根结点路径上第一个不小于当前结点权值的结点”的操作,st_sum[i][j]表示跳的过程中所有经过结点(不包括起点)的权值之和。能这样维护的原因是:操作2中的序列其实是唯一的,我只要能快速维护找到下一个结点的操作就行。这样倍增的轮廓就出来了,但是还有一件事要解决:第一步也就是st[i][0]怎么计算?这里就要用到二分的思想了:设tmp为i的父亲,利用二分锁定离i最近的符合要求的点,具体怎么实现就不用多说了,我想说的是我原本的写法:我原来写的是由i的父亲一步一步按st[tmp][0]的方式往上跳,实测两种写法没有任何时间上的差别,但是复杂度肯定是不一样的。。
代码随便看看。。
1 /* Codeforces 932D Tree 2 1st Edition:2018.2.15 Thursday 3 2nd Edition:2018.2.16 Friday 4 Algorithm:倍增 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <algorithm> 9 #include <cmath> 10 #include <cstring> 11 #include <vector> 12 #include <map> 13 #include <set> 14 #include <bitset> 15 #include <queue> 16 #include <deque> 17 #include <stack> 18 #include <iomanip> 19 #include <cstdlib> 20 #include <ctime> 21 #include <cctype> 22 using namespace std; 23 24 #define is_lower(c) (c>='a' && c<='z') 25 #define is_upper(c) (c>='A' && c<='Z') 26 #define is_alpha(c) (is_lower(c) || is_upper(c)) 27 #define is_digit(c) (c>='0' && c<='9') 28 #define stop system("PAUSE") 29 #define ForG(a,b,c) for(rg int (a)=c.head[b];(a);(a)=c.E[a].nxt) 30 #define For(a,b,c) for(rg int (a)=(b);(a)<=(c);++a) 31 #define min(a,b) ((a)<(b)?(a):(b)) 32 #define max(a,b) ((a)>(b)?(a):(b)) 33 #define shl(x,y) ((x)<<(y)) 34 #define shr(x,y) ((x)>>(y)) 35 #define mp make_pair 36 #define pb push_back 37 #define rg register 38 #ifdef ONLINE_JUDGE 39 #define hash rename_hash 40 #define next rename_next 41 #define prev rename_prev 42 #endif 43 typedef long long ll; 44 typedef unsigned long long ull; 45 typedef pair<int,int> pii; 46 typedef pair<ll,ll> pll; 47 typedef vector<int> vi; 48 typedef double db; 49 const ll inf=1000000007LL; 50 const db EPS=1e-14; 51 const ll inf_ll=(ll)1e18; 52 const ll maxn=400005LL; 53 const ll mod=1000000007LL; 54 55 int n,cnt; 56 ll last; 57 ll weight[maxn],sum[maxn][20]; 58 int par[maxn],st[maxn][20]; 59 60 int main(){ 61 scanf("%d",&n); 62 cnt=1; 63 while(n--){ 64 ll opt,p,q; 65 scanf("%I64d %I64d %I64d",&opt,&p,&q); 66 p^=last;q^=last; 67 if(opt^2){ 68 par[++cnt]=p; 69 weight[cnt]=q; 70 int tmp=p; 71 if(weight[tmp]<q){ 72 for(int i=19;i+1;--i) if(st[tmp][i] && weight[st[tmp][i]]<q){ 73 tmp=st[tmp][i]; 74 } 75 tmp=st[tmp][0]; 76 } 77 st[cnt][0]=tmp; 78 sum[cnt][0]=weight[tmp]; 79 For(i,1,19) if(st[cnt][i-1] && st[st[cnt][i-1]][i-1]){ 80 st[cnt][i]=st[st[cnt][i-1]][i-1]; 81 sum[cnt][i]=sum[cnt][i-1]+sum[st[cnt][i-1]][i-1]; 82 } 83 }else{ 84 ll nowsum=weight[p]; 85 if(nowsum>q){ 86 puts("0"); 87 last=0; 88 continue; 89 } 90 int now=p,res=1; 91 for(int i=19;i>=0;--i) if(st[now][i] && sum[now][i]+nowsum<=q){ 92 nowsum+=sum[now][i]; 93 now=st[now][i]; 94 res+=shl(1,i); 95 } 96 printf("%d ",res); 97 last=(ll)res; 98 } 99 } 100 return 0; 101 }