zoukankan      html  css  js  c++  java
  • BZOJ3091: 城市旅行

    BZOJ3091: 城市旅行

    Description

    Input

    Output

    Sample Input

    4 5
    1 3 2 5
    1 2
    1 3
    2 4
    4 2 4
    1 2 4
    2 3 4
    3 1 4 1
    4 1 4

    Sample Output

    16/3
    6/1

    HINT

    对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N


    题解Here!

    怎么$LCT$还套了一个数学期望啊。。。
    $LCT$的大框架没争论。
    然后看没有修改怎么办。
    也就是那个期望值怎么求。
    设每个点的权值为$val_i$。
    对于一条路径:$1-2-3-cdots-n$
    子路径数为$C^2_{n+1}$。
    也就是任选两个点,包括两个点重复。
    然后对于每个点$i$,一定会被$i imes(n-i+1)$条路径覆盖。
    即:从左边选择端点或从右边选择端点或选$i$为端点。
    所以它的贡献就是$val_i imes i imes(n-i+1)$。
    于是期望值就可以这么算:$$exp=frac{sum_{i=1}^n(val_i imes i imes (n-i+1))}{C^2_{n+1}}$$
    但是这玩意怎么维护呢?
    那个分母直接维护$size$即可,所以丢一边去不管它。
    再画图:
    对于一条树上路径:$1-2-3-cdots-x-(x+1)-(x+2)-cdots-n$
    假设$x$为根节点。
    那么左子树为:$1-2-3-cdots-(x-1)$
    其期望值为:$$exp_{lson}=sum_{i=1}^{x-1}(val_i imes i imes (x-i))$$
    但是实际要求的贡献为:$$exp_{lson}'=sum_{i=1}^{x-1}(val_i imes i imes (n-i+1))$$
    这个怎么办呢?
    我们作个差试试:$$left.egin{array}{}exp_{lson}'-exp_{lson}&=&sum_{i=1}^{x-1}(val_i imes i imes ((n-i+1)-(x-i)))\&=&(n-x+1)sum_{i=1}^{x-1}(val_i imes i)end{array} ight.$$
    额。。。好像没什么用啊。。。
    等一下!
    那个$(n-x+1)$很可疑啊!
    没错!它就是右子树的$size+1$!(那个$1$是根节点)
    设:$$lsum_n=sum_{i=1}^n(val_i imes i)$$
    所以:$$exp_{lson}'=exp_{lson}+lsum_{lson} imes(size_{rson}+1)$$
    同理对于右子树:
    $$rsum_n=sum_{i=1}^n(val_i imes (n-i+1))$$
    $$exp_{rson}'=exp_{rson}+rsum_{rson} imes(size_{lson}+1)$$
    然后是根节点的贡献:$$exp_{rt}'=val_{rt} imes(size_{lson}+1) imes(size_{rson}+1)$$
    整到一块去:$$left.egin{array}{}exp_{rt}&=&exp_{rt}'+exp_{lson}'+exp_{rson}'\&=&exp_{lson}+lsum_{lson} imes(size_{rson}+1)+exp_{rson}+rsum_{rson} imes(size_{lson}+1)+val_{rt} imes(size_{lson}+1) imes(size_{rson}+1)end{array} ight.$$
    那,$lsum_{rt},rsum_{rt}$怎么维护呢?
    也很简单:
    设$$sum_{rt}=sum_{iin son_{rt}}val_i$$
    则:$$lsum_{rt}=lsum_{lson}+lsum_{rson}+(val_{rt}+sum_{rson}) imes(size_{lson}+1)$$
    $$rsum_{rt}=rsum_{lson}+rsum_{rson}+(sum_{lson}+val_{rt}) imes(size_{rson}+1)$$
    终于把数学期望搞定了。。。
    等一下!
    好像还有修改?!
    蒟蒻心里苦。。。
    继续慢慢推式子。。。
    假设在$rt$加上的值为$c$。
    很显然:$$val_{rt}+=c$$
    $$sum_{rt}+=c imes size_{rt}$$
    那个$lsum_{rt},rsum_{rt}$推一推式子也能出来:
    $$lsum_{rt}'=sum_{iin son_{rt}}((val_i+c) imes i)=sum_{iin son_{rt}}(val_i imes i)+c imes frac{size_{rt}(size_{rt}+1)}{2}=lsum_{rt}+c imes frac{size_{rt}(size_{rt}+1)}{2}$$
    $$rsum_{rt}'=rsum_{rt}+c imes frac{size_{rt}(size_{rt}+1)}{2}$$
    但是$exp_{rt}$就很恶心了。。。
    与$lsum_{rt}$的方法相同,我们可以得到:$$exp_{rt}'=exp_{rt}+c imes sum_{i=1}^{size_{rt}}(i imes(size_{rt}-i+1))$$
    后面那一堆看得很烦,于是挑出来搞事:$$S=sum_{i=1}^{n}(i imes(n-i+1))=1 imes n+2 imes (n-1)+cdots+n imes 1$$
    补项成我们会的东东:$$S=(1+2+3+cdots+n) imes n-(1 imes 2+2 imes 3+cdots+(n-1) imes n)$$
    前面一部分好说,继续把后面一部分挑出来搞事:
    $$S=frac{n^2(n+1)}{2}-W$$
    $$W=(1 imes 2+2 imes 3+cdots+(n-1) imes n)$$
    拆项成我们会的东东:
    $$left.egin{array}{}W&=&1 imes 2+2 imes 3+cdots+(n-1) imes n\&=&1^2+2^2+3^2+cdots+(n-1)^2+1+2+3+cdots+(n-1)end{array} ight.$$
    根据小学奥数/高中必修,我们可以得到:$$W=frac{n(n-1)(2n-1)}{6}+frac{n(n-1)}{2}$$
    于是:$$S=frac{n^2(n+1)}{2}-frac{n(n-1)(2n-1)}{6}-frac{n(n-1)}{2}$$
    然后疯狂展开,疯狂合并同类项,最后得到一个简单到难以想象的式子:$$S=frac{n(n+1)(n+2)}{6}$$
    整个还回去:$$exp_{rt}'=exp_{rt}+c imesfrac{size_{rt}(size_{rt}+1)(size_{rt}+2)}{6}$$
    修改也就完成了。
    记得翻转的时候把$lsum_{rt},rsum_{rt}$也交换一下。
    然后用一个$map$大力记录边。
    记得开$long long$。
    呼~~~
    终于写完了。。。
    累死我了。。。
    鬼畜的神题。。。
    其实我写的还不是很好,但是我已经尽力了。。。
    看不懂的,就去找代码吧。。。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<map>
    #define MAXN 50010
    using namespace std;
    map<int,int> Edge[MAXN];
    int n,m;
    int top=0,stack[MAXN];
    struct Link_Cut_Tree{
    	int f,size,flag,son[2];
    	long long val,sum,lsum,rsum,exp,c;//exp==expectation
    }a[MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    long long gcd(long long x,long long y){
    	if(!y)return x;
    	return gcd(y,x%y);
    }
    inline bool isroot(int rt){
    	return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
    }
    inline void pushup(int rt){
    	if(!rt)return;
    	int lson=a[rt].son[0],rson=a[rt].son[1];
    	a[rt].sum=a[lson].sum+a[rson].sum+a[rt].val;
    	a[rt].size=a[lson].size+a[rson].size+1;
    	a[rt].lsum=a[lson].lsum+a[rson].lsum+(a[rt].val+a[rson].sum)*(a[lson].size+1);
    	a[rt].rsum=a[rson].rsum+a[lson].rsum+(a[lson].sum+a[rt].val)*(a[rson].size+1);
    	a[rt].exp=a[lson].exp+a[rson].exp+a[rt].val*(a[lson].size+1)*(a[rson].size+1)+a[lson].lsum*(a[rson].size+1)+a[rson].rsum*(a[lson].size+1);
    }
    inline void reverse(int rt){
    	if(!rt)return;
    	a[rt].flag^=1;
    	swap(a[rt].son[0],a[rt].son[1]);
    	swap(a[rt].lsum,a[rt].rsum);
    }
    inline void change(int rt,long long c){
    	if(!rt)return;
    	long long x=1LL*a[rt].size*(a[rt].size+1)/2,y=1LL*a[rt].size*(a[rt].size+1)*(a[rt].size+2)/6;
    	a[rt].val+=c;
    	a[rt].c+=c;
    	a[rt].sum+=c*a[rt].size;
    	a[rt].lsum+=x*c;
    	a[rt].rsum+=x*c;
    	a[rt].exp+=c*y;
    }
    inline void pushdown(int rt){
    	if(!rt)return;
    	if(a[rt].flag){
    		reverse(a[rt].son[0]);
    		reverse(a[rt].son[1]);
    		a[rt].flag=0;
    	}
    	if(a[rt].c){
    		change(a[rt].son[0],a[rt].c);
    		change(a[rt].son[1],a[rt].c);
    		a[rt].c=0;
    	}
    }
    inline void turn(int rt){
    	int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
    	if(!isroot(x)){
    		if(a[y].son[0]==x)a[y].son[0]=rt;
    		else a[y].son[1]=rt;
    	}
    	a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
    	a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
    	pushup(x);pushup(rt);
    }
    void splay(int rt){
    	top=0;
    	stack[++top]=rt;
    	for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
    	while(top)pushdown(stack[top--]);
    	while(!isroot(rt)){
    		int x=a[rt].f,y=a[x].f;
    		if(!isroot(x)){
    			if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
    			else turn(x);
    		}
    		turn(rt);
    	}
    }
    void access(int rt){
    	for(int i=0;rt;i=rt,rt=a[rt].f){
    		splay(rt);
    		a[rt].son[1]=i;
    		pushup(rt);
    	}
    }
    inline void makeroot(int rt){access(rt);splay(rt);reverse(rt);}
    int findroot(int rt){
    	access(rt);splay(rt);
    	while(a[rt].son[0])rt=a[rt].son[0];
    	return rt;
    }
    inline void split(int x,int y){makeroot(x);access(y);splay(y);}
    inline void link(int x,int y){makeroot(x);a[x].f=y;}
    inline void cut(int x,int y){
    	split(x,y);
    	if(a[y].son[0]==x&&a[x].f==y&&!a[x].son[1])a[x].f=a[y].son[0]=0;
    	pushup(y);
    }
    inline void update(int x,int y,int k){
    	split(x,y);
    	change(y,k);
    }
    inline void query(int x,int y){
    	long long on,down,t;
    	split(x,y);
    	on=a[y].exp;
    	down=1LL*a[y].size*(a[y].size+1)/2;
    	t=gcd(on,down);
    	printf("%lld/%lld
    ",on/t,down/t);
    }
    void work(){
    	int f,x,y,k;
    	while(m--){
    		f=read();x=read();y=read();
    		switch(f){
    			case 1:{
    				if(Edge[x][y]){
    					cut(x,y);
    					Edge[x][y]=Edge[y][x]=0;
    				}
    				break;
    			}
    			case 2:{
    				if(findroot(x)!=findroot(y)){
    					link(x,y);
    					Edge[x][y]=Edge[y][x]=1;
    				}
    				break;
    			}
    			case 3:{
    				k=read();
    				if(findroot(x)!=findroot(y))break;
    				update(x,y,k);
    				break;
    			}
    			case 4:{
    				if(findroot(x)!=findroot(y))printf("-1
    ");
    				else query(x,y);
    				break;
    			}
    		}
    	}
    }
    void init(){
    	int x,y;
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		a[i].val=read();
    		pushup(i);
    	}
    	for(int i=1;i<n;i++){
    		x=read();y=read();
    		Edge[x][y]=Edge[y][x]=1;
    		link(x,y);
    	}
    }
    int main(){
    	init();
    	work();
        return 0;
    }
  • 相关阅读:
    【高软作业4】:Tomcat 观察者模式解析 之 Lifecycle
    Eclipse 导入 Tomcat 源码
    【高软作业3】:原型化系统 DevTools
    Java Obejct
    Java PriorityQueue
    【高软作业2】:Java IDE调研分析
    GitHub fork 合作开发 快速实现版
    用C#实现天气预报(调用WebService)
    hover和点击事件之间的冲突
    BurpSuite2021系列(三)新建扫描
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/10467842.html
Copyright © 2011-2022 走看看