bzoj3786: 星系探索
Description
物理学家小C的研究正遇到某个瓶颈。
他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球。主星球没有依赖星球。
我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c.
对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的。并且从星球a出发只能直接到达它的依赖星球b.
每个星球i都有一个能量系数wi.小C想进行若干次实验,第i次实验,他将从飞船上向星球di发射一个初始能量为0的能量收集器,能量收集器会从星球di开始前往主星球,并收集沿途每个星球的部分能量,收集能量的多少等于这个星球的能量系数。
但是星系的构成并不是一成不变的,某些时刻,星系可能由于某些复杂的原因发生变化。
有些时刻,某个星球能量激发,将使得所有依赖于它的星球以及他自己的能量系数均增加一个定值。还有可能在某些时刻,某个星球的依赖星球会发生变化,但变化后依然满足依赖关系是无环的。
现在小C已经测定了时刻0时每个星球的能量系数,以及每个星球(除了主星球之外)的依赖星球。接下来的m个时刻,每个时刻都会发生一些事件。其中小C可能会进行若干次实验,对于他的每一次实验,请你告诉他这一次实验能量收集器的最终能量是多少。
Input
第一行一个整数n,表示星系的星球数。
接下来n-1行每行一个整数,分别表示星球2-n的依赖星球编号。
接下来一行n个整数,表示每个星球在时刻0时的初始能量系数wi.
接下来一行一个整数m,表示事件的总数。
事件分为以下三种类型。
(1)"Q di"表示小C要开始一次实验,收集器的初始位置在星球di.
(2)"C xi yi"表示星球xi的依赖星球变为了星球yi.
(3)"F pi qi"表示星球pi能量激发,常数为qi.
Output
对于每一个事件类型为Q的事件,输出一行一个整数,表示此次实验的收集器最终能量。
Sample Input
3
1
1
4 5 7
5
Q 2
F 1 3
Q 2
C 2 3
Q 2
Sample Output
9
15
25
HINT
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保证操作合法。注意w_i>=0
Source
solution
欧拉序+splay
子树修改很难实现啊,怎么办呢?
任神犇:欧拉序,第一次的记为正,第二次记为负,这样子维护前缀和就可以了。
orz!!
如神犇所说,按欧拉序为下标建splay,支持区间修改,区间交换。
当时想了很久都在想一个问题:我区间都换了,欧拉序也变了,那怎么才能把点找出来呢?
首先,明确:
tr[x]维护着欧拉序为x的答案,这是不会变的。
而树结构的改变,意味着欧拉序的改变。
也就是我们已知欧拉序,就可以取出一个点(虽然我不知道它在树的哪里)
那我沿着这个点往根跳,就可以知道有多少个点比他小,也就是它排在第几位了
然后就很方便啦。
注意:
1.欧拉序下标最好从2开始,不然很麻烦
2.因为要严格按欧拉序建树,建时直接就是tr[mid]=W[mid]..
3.注意w为0的情况
4,swap取L[y]时要推标记(kth)
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 200005
#define ll long long
#define inf 1e9
using namespace std;
int n,m,head[maxn],L[maxn],R[maxn],w[maxn],W[maxn],tot;
int sc=1,root;
struct node{
int v,nex;
}e[maxn];
struct no{
int ch[2],f,tp,sz;
ll v,bj,sum,stp;
}tr[maxn];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k){
L[k]=++sc;w[sc]=(W[k]!=0)?W[k]:inf;
for(int i=head[k];i;i=e[i].nex){
dfs(e[i].v);
}
R[k]=++sc;w[sc]=(W[k]!=0)?-W[k]:-inf;
}
int get(int x){
return tr[tr[x].f].ch[1]==x;
}
void wh(int k){
if(!k)return;
int ls=tr[k].ch[0],rs=tr[k].ch[1];
tr[k].sum=tr[ls].sum+tr[rs].sum+tr[k].v;
tr[k].stp=tr[ls].stp+tr[rs].stp+tr[k].tp;
tr[k].sz=tr[ls].sz+tr[rs].sz+1;
}
void update(int k,ll v){
if(!k)return;
tr[k].bj+=v;tr[k].sum+=tr[k].stp*v;
tr[k].v+=tr[k].tp*v;
}
void down(int k){
if(tr[k].bj){
update(tr[k].ch[0],tr[k].bj);
update(tr[k].ch[1],tr[k].bj);
tr[k].bj=0;
}
}
int build(int fa,int l,int r){
if(l>r)return 0;
int mid=l+r>>1,k=mid;
tr[k].f=fa;tr[k].v=tr[k].sum=(w[k]!=inf&&w[k]!=-inf)?w[k]:0;
tr[k].tp=tr[k].stp=(w[k]>0?1:-1);
tr[k].ch[0]=build(k,l,mid-1);
tr[k].ch[1]=build(k,mid+1,r);
wh(k);return k;
}
int find(int x){// Å·ÀÐòxÊǵڼ¸´óµÄÊý
int sum=tr[tr[x].ch[0]].sz;
while(x!=root){
if(get(x))sum+=tr[tr[tr[x].f].ch[0]].sz+1;
x=tr[x].f;
}
return sum+1;
}
int Kth(int x){// µÚx´óÊÇË
int k=root;
while(1){
down(k);
//cout<<k<<' '<<x<<endl;
int ls=tr[k].ch[0];
if(tr[ls].sz>=x)k=ls;
if(tr[ls].sz==x-1)return k;
if(tr[ls].sz<x-1)x-=tr[ls].sz+1,k=tr[k].ch[1];
}
}
void rotate(int x){
int y=tr[x].f,z=tr[y].f;
int wx=get(x),wy=get(y);
tr[z].ch[wy]=x;tr[x].f=z;
tr[y].ch[wx]=tr[x].ch[wx^1];tr[tr[x].ch[wx^1]].f=y;
tr[x].ch[wx^1]=y;tr[y].f=x;
wh(y),wh(x);
}
void splay(int x,int g){
while(tr[x].f!=g){
int y=tr[x].f,z=tr[y].f;
if(z!=g)rotate(get(x)==get(y)?y:x);
rotate(x);
}
if(!g)root=x;
}
void print_tr(int k){
if(!k)return;
down(k);
print_tr(tr[k].ch[0]);
printf("k:%d v:%d sum:%d tp:%d sz:%d f:%d\n",k,tr[k].v,tr[k].sum,tr[k].tp,tr[k].sz,tr[k].f);
print_tr(tr[k].ch[1]);
}
int main(){
cin>>n;
for(int i=2,t;i<=n;i++)scanf("%d",&t),lj(t,i);
for(int i=1;i<=n;i++)scanf("%d",&W[i]);
dfs(1);
//for(int i=1;i<=n;i++)cout<<L[i]<<' '<<R[i]<<endl;
root=build(0,1,n+n+2);
scanf("%d",&m);
for(int i=1,x,y;i<=m;i++){
char op;scanf(" %c",&op);
if(op=='Q'){
scanf("%d",&x);
int a=Kth(find(L[x])+1);
//cout<<"a "<<a<<' '<<x<<' '<<L[x]<<' '<<find(L[x])<<endl;
splay(a,0);//print_tr(root);
printf("%lld\n",tr[tr[root].ch[0]].sum);
}
if(op=='C'){
scanf("%d%d",&x,&y);
int a=Kth(find(L[x])-1),b=Kth(find(R[x])+1);
//cout<<a<<' '<<b<<endl;
splay(a,0);splay(b,a);
//print_tr(root);
int t=tr[tr[root].ch[1]].ch[0];
tr[tr[root].ch[1]].ch[0]=0;
wh(tr[root].ch[1]),wh(root);
a=Kth(find(L[y])),b=Kth(find(L[y])+1);
splay(a,0);splay(b,a);
tr[tr[root].ch[1]].ch[0]=t;tr[t].f=tr[root].ch[1];
wh(tr[root].ch[1]),wh(root);
}
if(op=='F'){
scanf("%d%d",&x,&y);
int a=Kth(find(L[x])-1),b=Kth(find(R[x])+1);
//cout<<"a b:"<<a<<' '<<b<<endl;
splay(a,0);splay(b,a);
int t=tr[tr[root].ch[1]].ch[0];
update(t,y);
//print_tr(root);
}
}
return 0;
}