zoukankan      html  css  js  c++  java
  • 2017 山东二轮集训 Day7 国王

    2017 山东二轮集训 Day7 国王

    题目大意

    给定一棵树,每个点有黑白两种颜色,定义一条简单路径合法当且仅当路径上所有点黑色与白色数量相等,求有多少非空区间 ([L,R]) ,使得所有编号 (in[L,R]) 的点形成的本质不同的合法简单路径数多于所有编号 ( otin[L,R]) 的点形成的本质不同的合法路径树。

    题解

    考虑所有以 (x) 为一个端点的合法简单路径数量为 (F_x)
    设两端点编号分别位于 ([L,R]) 之内和之外的路径树为 (M)
    那么 ([L,R]) 合法当且仅当 (sumlimits_{xin[L,R]} F_x-M>sumlimits_{x otin[L,R]} F_x-M)
    (sumlimits_{xin[L,R]} F_x>sumlimits_{x otin[L,R]} F_x)
    显然可以轻松的点分治求出 (F_x) ,然后随着 (R) 的增大, 极大的合法的 (L) 显然单调不减,所以类似滑动窗口一样的求就可以了。

    #include<bits/stdc++.h>
    #define debug(x) cerr<<#x<<" = "<<x
    #define sp <<"  "
    #define el <<endl
    #define fgx cerr<<"-----------------------------------"<<endl
    #define LL long long
    #define M 100010
    using namespace std;
    namespace IO{
    	const int BS=(1<<23)+5; int Top=0;
    	char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
    	char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
    	void flush(){fwrite(OT,1,OS-OT,stdout),OS=OT;}
    	void Putchar(char c){*OS++ =c;if(OS==fin)flush();}
    	void write(int x){
    		if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
    		while(x) SS[++Top]=x%10,x/=10;
    		while(Top) Putchar(SS[Top]+'0'),--Top;
    	}
    	int read(){
    		int nm=0,fh=1; char cw=Getchar();
    		for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    		for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    		return nm*fh;
    	}
    } using namespace IO;
    int G[M<<1],mxs[M],n,m,fs[M],nt[M<<1],to[M<<1],tmp,F[M],V[M],sz[M]; bool vis[M]; LL ans=0; 
    inline void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
    #define rep for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]!=last&&!vis[to[i]])
    void fdrt(int x,int last,int all,int &RT){
    	mxs[x]=0,sz[x]=1; rep fdrt(to[i],x,all,RT),sz[x]+=sz[to[i]],mxs[x]=max(mxs[x],sz[to[i]]);
    	if((mxs[x]=max(mxs[x],all-sz[x]))<mxs[RT]) RT=x;
    }
    int init(int x,int last,int val){int res=abs(val+=V[x]);G[val+M]++,sz[x]=1;rep res=max(res,init(to[i],x,val)); return res;}
    void getans(int x,int last,int val,int fh){sz[x]=1,val+=V[x],F[x]+=fh*G[M-val]; rep getans(to[i],x,val,fh),sz[x]+=sz[to[i]];}
    inline void calc(int x,int last,int fh){
    	int len=init(x,last,last?V[last]:0)+1; getans(x,last,last?0:-V[x],fh);
    	for(int i=-len;i<=len;i++) G[i+M]=0;
    }
    void solve(int x,int all){
    	if(all==1){vis[x]=true;return;}int RT=0,last=0;fdrt(x,0,all,RT),x=RT;
    	vis[x]=true,calc(x,0,1); rep calc(to[i],x,-1); rep solve(to[i],sz[to[i]]);
    }
    int main(){
    	n=read(),memset(fs,-1,sizeof(fs)),mxs[0]=n;
    	for(int i=1;i<=n;i++) V[i]=(read()<<1)-1;
    	for(int i=1,x,y;i<n;i++) x=read(),y=read(),link(x,y),link(y,x);
    	solve(1,n); LL sum=0; for(int i=1;i<=n;i++) sum+=F[i]; sum>>=1;
    	for(int l=1,r=1,now=F[1];r<=n;r++,now+=F[r]){while(now>sum) now-=F[l++]; ans+=l-1;}
    	printf("%lld
    ",ans); return 0;
    }
    
  • 相关阅读:
    CentOS7 搭建php环境
    多tomcat服务和nginx负载均衡配置
    linux grep命令
    centos7 远程连接其他服务器redis
    centos7 远程连接其他服务器mysql
    关于结构体对齐
    c语言打印一个整数的二进制形式
    c语言判断一个数是否为偶数
    vim的窗口切换
    pow(x,y)函数的实现算法(递归函数)
  • 原文地址:https://www.cnblogs.com/OYJason/p/10619106.html
Copyright © 2011-2022 走看看