• 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

    By 佚名上传


    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
    ",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
    ",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;
    }
    
  • 相关阅读:
    资源:mysql下载路径
    知识点:jar包与war包的差异
    Linux:jar服务部署
    Flyway:Spring Boot中使用Flyway来管理数据库版本
    Java:Java控制台输出保存进文件
    Maven:手动添加jar包进Maven本地库内
    Https:SSL双向认证机制(理论知识)
    Linux ubuntu 下寻找 texlive 缺失包 texlive 缺失包(转载)
    Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)
    Android应用开发基础篇(12)-----Socket通信(转载)
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358745.html
Copyright © 2020-2023  润新知