zoukankan      html  css  js  c++  java
  • 点分治

    点分治:

    通常用来处理树上路径信息,选出部分,把部分的全部处理更新答案,用部分与部分之间的联系求出整体。

    一般,我们选择重心作为分治对象。

    对两个不属于统一部份的进行合并的时候,我们通常需要预处理出到分治中心的信息,再对这种信息进行合并。

    点分治很多题的关键在于容斥原理,容斥原理通常能够排除掉很多不正确的

    BZOJ1468 Tree

    存一下每个点到分治中心的距离,双指针扫一下求出所有满足题意的路径,再减去子树中自己本身的

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <iostream>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    using namespace std;
    #define N 400005
    #define ll long long
    int head[N],cnt,siz[N],maxx[N],rot,num,ans,n;
    ll dep[N],K;
    struct node
    {
    	int to,next,val;
    }e[N<<1];
    bool vis[N];
    void add(int x,int y,int z)
    {
    	e[++cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt;
    	return ;
    }
    void get_root(int x,int from)
    {
    	maxx[x]=0,siz[x]=1;
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&(!vis[to1]))
    		{
    			get_root(to1,x);
    			siz[x]+=siz[to1];
    			maxx[x]=max(maxx[x],siz[to1]);
    		}
    	}
    	maxx[x]=max(maxx[x],num-siz[x]);
    	if(maxx[rot]>maxx[x])rot=x;
    }
    ll a[N];
    int cnt1;
    void get_dep(int x,int from)
    {
    	a[++cnt1]=dep[x];
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&(!vis[to1]))
    		{
    			dep[to1]=dep[x]+e[i].val;
    			get_dep(to1,x);
    		}
    	}
    }
    int calc(int x)
    {
    	int sum=0;
    	cnt1=0;
    	get_dep(x,0);
    	sort(a+1,a+cnt1+1);
    	int h=1,t=cnt1;
    	while(h<t)
    	{
    		if(a[t]+a[h]>K)t--;
    		else 
    		{
    			sum+=t-h;
    			h++;
    		}
    	}
    	return sum;
    }
    void dfs(int x)
    {
    	dep[x]=0,vis[x]=1;ans+=calc(x);
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(!vis[to1])
    		{
    			dep[to1]=e[i].val;
    			ans-=calc(to1);
    			num=siz[to1];
    			rot=0;
    			get_root(to1,x);
    			dfs(rot);
    		}
    	}
    }
    char s[2];
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for(int i=1;i<n;i++)
    	{
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    	}
    	num=n;
    	scanf("%d",&K);
    	maxx[0]=1<<30;
    	get_root(1,0);
    	dfs(rot);
    	printf("%d
    ",ans);
    	return 0;
    }

    BZOJ2152 聪聪可可

    求恰好是3的倍数,那么我们存一下到根的距离为%3==0,%3==1,%3==2的方案数,最后合计一下更新答案就好了,注意细节。

    附上代码:

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    #define N 20005
    #define ll long long
    int head[N],cnt,siz[N],sn,rot,mx[N],n;
    ll ans,f[3],dep[N];
    bool vis[N];
    struct node
    {
    	int to,next,val;
    }e[N<<1];
    void add(int x,int y,int z)
    {
    	e[++cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt;
    	return ;
    }
    void getroot(int x,int from)
    {
    	siz[x]=1,mx[x]=0;
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&(!vis[to1]))
    		{
    			getroot(to1,x);
    			siz[x]+=siz[to1];
    			mx[x]=max(mx[x],siz[to1]);
    		}
    	}
    	mx[x]=max(mx[x],sn-siz[x]);
    	if(mx[x]<mx[rot])rot=x;
    	return ;
    }
    void get_dep(int x,int from)
    {
    	f[dep[x]]++;
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&(!vis[to1]))
    		{
    			dep[to1]=(dep[x]+e[i].val)%3;
    			get_dep(to1,x);
    		}
    	}
    }
    ll calc(int x)
    {
    	f[0]=0,f[1]=0,f[2]=0;
    	get_dep(x,0);
    	return (f[0]*f[0])+(2*f[1]*f[2]);
    }
    void dfs(int x)
    {
    	dep[x]=0;vis[x]=1;ans+=calc(x);
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(!vis[to1])
    		{
    			dep[to1]=e[i].val;
    			ans-=calc(to1);
    			sn=siz[to1];
    			rot=0;
    			getroot(to1,0);
    			dfs(rot);
    		}
    	}
    }
    ll gcd(ll a,ll b)
    {
    	if(!b)return a;
    	return gcd(b,a%b);
    }
    int main()
    {
    	memset(vis,0,sizeof(vis));
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for(int i=1;i<n;i++)
    	{
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z%3);
    		add(y,x,z%3);
    	}
    	mx[0]=1<<30;
    	sn=n;
    	getroot(1,0);
    	dfs(rot);
    	ll t=gcd(ans,n*n);
    	printf("%lld/%lld
    ",ans/t,n*n/t);
    	return 0;
    }
    

    BZOJ3697: 采药人的路径

    其实这个题挺有趣的,我们可以考虑,如果没有限制2的话,和上道题差不多,那么现在我们考虑加上条件二,什么样的路径可以更新答案呢?我们可以考虑,更新的时候加上一个限制,就是判断是否可以满足有一个中间点,容斥原理减掉多余的,什么时候存在中间点呢?我们就是这条路径的长度包涵在已经有长度的区间中,至于为什么正确,因为容斥的时候会将不正确的排除掉,剩下的就是同样的东西了,关键就在第二问。

    附上代码:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    #define N 100005
    #define ll long long
    int siz[N],mx[N],head[N],cnt,tot,sn,rot,vis[N],n,len;
    struct node
    {
        int to,next,val;
    }e[N<<1];
    ll ans,f[N][2],g[N][2];
    void add(int x,int y,int z)
    {
        e[cnt].to=y;
        e[cnt].val=z;
        e[cnt].next=head[x];
        head[x]=cnt++;
    }
    void get_root(int x,int from)
    {
        siz[x]=1;mx[x]=0;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                get_root(to1,x);
                siz[x]+=siz[to1];
                mx[x]=max(mx[x],siz[to1]);
            }
        }
        mx[x]=max(mx[x],sn-siz[x]);
        if(mx[rot]>mx[x])rot=x;
    }
    void calc(int x,int from,int now,int cnt)
    {
        if(now==0)
        {
            if(cnt>=2)ans++;
            cnt++;
        }
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                calc(to1,x,now+e[i].val,cnt);
            }
        }
    }
    void get_dep(int x,int from,int now,int l,int r)
    {
        if(l<=now&&now<=r)
        {
            if(now>=0)f[now][1]++;
            else g[-now][1]++;
        }else
        {
            if(now>=0)f[now][0]++;
            else g[-now][0]++;
        }
        l=min(l,now);r=max(r,now);len=max(max(r,-l),len);
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(!vis[to1]&&to1!=from)
            {
                get_dep(to1,x,now+e[i].val,l,r);
            }
        }
    }
    void dfs(int x)
    {
        vis[x]=1;calc(x,0,0,0);
        get_dep(x,0,0,1,-1),ans+=f[0][1]*(f[0][1]-1)/2;f[0][0]=f[0][1]=0;
        for(int i=1;i<=len;i++)ans+=f[i][0]*g[i][1]+g[i][0]*f[i][1]+f[i][1]*g[i][1],f[i][0]=f[i][1]=g[i][1]=g[i][0]=0;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(!vis[to1])
            {
                len=0;get_dep(to1,0,e[i].val,0,0);ans-=f[0][1]*(f[0][1]-1)/2;f[0][1]=f[0][0]=0;
                for(int i=0;i<=len;i++)ans-=f[i][0]*g[i][1]+g[i][0]*f[i][1]+f[i][1]*g[i][1],f[i][0]=f[i][1]=g[i][1]=g[i][0]=0;
                sn=siz[to1];
                rot=0;get_root(to1,0);
                dfs(rot);
            }
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z*2-1);
            add(y,x,z*2-1);
        }
        sn=n;mx[0]=n;
        get_root(1,0);
        dfs(rot);
        printf("%lld
    ",ans);
        return 0;
    }
    

    BZOJ1316: 树上的询问

    同样的原理,get_dep之后处理长度,就是需要离线一下,每次处理出所有答案的结果,关键在离线,在线的话时间复杂度会有毛病。

    附上代码:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    using namespace std;
    #define N 10005
    #define ll long long
    int siz[N],mx[N],head[N],cnt,tot,sn,rot,vis[N],n,len,a[105],dep[N],d[N],Q,p[N];
    struct node
    {
    	int to,next,val;
    }e[N<<1];
    bool ans[105],b[1000005];
    void add(int x,int y,int z)
    {
    	e[cnt].to=y;
    	e[cnt].val=z;
    	e[cnt].next=head[x];
    	head[x]=cnt++;
    }
    void get_root(int x,int from)
    {
    	siz[x]=1;mx[x]=0;
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&!vis[to1])
    		{
    			get_root(to1,x);
    			siz[x]+=siz[to1];
    			mx[x]=max(mx[x],siz[to1]);
    		}
    	}
    	mx[x]=max(mx[x],sn-siz[x]);
    	if(mx[rot]>mx[x])rot=x;
    }
    void get_dep(int x,int from)
    {
    	d[++tot]=dep[x];
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(to1!=from&&!vis[to1])
    		{
    			dep[to1]=dep[x]+e[i].val;
    			get_dep(to1,x);
    		}
    	}
    }
    void calc(int x)
    {
    	b[0]=1;int cnt1=0;
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(!vis[to1])
    		{
    			tot=0;dep[to1]=e[i].val;
    			get_dep(to1,0);
    			for(int j=1;j<=tot;j++)
    			{
    				for(int k=1;k<=Q;k++)
    				{
    					if(a[k]>=d[j]&&b[a[k]-d[j]])
    					{
    						ans[k]=1;
    					}
    				}
    			}
    			for(int j=1;j<=tot;j++)
    			{
    				if(d[j]<=1000000)
    				{
    					p[++cnt1]=d[j];
    					b[d[j]]=1;
    				}
    			}
    		}
    	}
    	for(int i=1;i<=cnt1;i++)b[p[i]]=0;
    }
    void dfs(int x)
    {
    	vis[x]=1;
    	get_dep(x,0);
    	calc(x);
    	for(int i=head[x];i!=-1;i=e[i].next)
    	{
    		int to1=e[i].to;
    		if(!vis[to1])
    		{
    			sn=siz[to1];
    			rot=0;get_root(to1,0);
    			dfs(rot);
    		}
    	}
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&Q);
    	for(int i=1;i<n;i++)
    	{
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    	}
    	for(int i=1;i<=Q;i++)
    	{
    		scanf("%d",&a[i]);
    		if(!a[i])ans[i]=1;
    	}
    	sn=n;mx[0]=1<<30;
    	get_root(1,0);
    	dfs(rot);
    	for(int i=1;i<=Q;i++)
    	{
    		if(ans[i])puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    

    BZOJ4016: [FJOI2014]最短路径树问题

    这个题,我已经无力吐槽了,这个题的难点在读题和求最短路树,Dijkstra找出最短路图,在最短路图上跑以最小字典序的树,就可以了。

    calc的时候树形DP求长度为K的最长链,状态f[i][j]表示节点i,选择j个节点的最长链,随便写写,当然,这个东西不用容斥原理了,其实点分治是可以优化一些树形DP的,例如这道题和下一道题。

    附上代码:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <set>
    #include <vector>
    using namespace std;
    #define N 30005
    #define ll long long
    int ans,ans1,siz[N],mx[N],head1[N],head[N],dep[N],cnt,cnt1,tot,sn,rot,vis[N],n,len,dis[N],K,m,num[N],f[N],g[N],num1[N];
    struct node
    {
        int to,next,val;
    }E[N<<2],e[N<<1];
    void add1(int x,int y,int z)
    {
        E[cnt1].to=y;
        E[cnt1].val=z;
        E[cnt1].next=head1[x];
        head1[x]=cnt1++;
        return ;
    }
    void add(int x,int y,int z)
    {
        e[cnt].to=y;
        e[cnt].val=z;
        e[cnt].next=head[x];
        head[x]=cnt++;
        return ;
    }
    priority_queue<pair<int,int> >q;
    vector<int> v[N];
    void dijkstra()
    {
        memset(dis,0x3f,sizeof(dis));
        dis[1]=0;
        q.push(make_pair(0,1));
        while(!q.empty())
        {
            int x=q.top().second;q.pop();
            if(vis[x])continue;
            vis[x]=1;
            for(int i=head1[x];i!=-1;i=E[i].next)
            {
                int to1=E[i].to;
                if(dis[x]==dis[to1]+E[i].val)
                {
                    v[to1].push_back(i^1);
                }
            }
            for(int i=head1[x];i!=-1;i=E[i].next)
            {
                int to1=E[i].to;
                if(dis[to1]>dis[x]+E[i].val)
                {
                    dis[to1]=dis[x]+E[i].val;
                    q.push(make_pair(-dis[to1],to1));
                }
            }
        }
    }
    bool cmp(int a,int b)
    {
        return E[a].to<E[b].to;
    }
    bool used[N];
    void build(int x)
    {
        sort(v[x].begin(),v[x].end(),cmp);
        for(int i=0;i<v[x].size();i++)
        {
            int to1=E[v[x][i]].to;
            if(!used[to1])
            {
                used[to1]=1;
                add(x,to1,E[v[x][i]].val);
                add(to1,x,E[v[x][i]].val);
                build(to1);
            }
        }
    }
    /*
    void prin(int x,int from)
    {
        printf("%d
    ",x);
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from)
            {
                prin(to1,x);
            }
        }
    }*/
    void get_root(int x,int from)
    {
        siz[x]=1;mx[x]=0;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                get_root(to1,x);
                siz[x]+=siz[to1];
                mx[x]=max(mx[x],siz[to1]);
            }
        }
        mx[x]=max(mx[x],sn-siz[x]);
        if(mx[rot]>mx[x])rot=x;
    }
    void get_dep(int x,int from)
    {
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                dep[to1]=dep[x]+1;dis[to1]=dis[x]+e[i].val;len=max(dep[to1],len);
                if(dis[to1]>f[dep[to1]])f[dep[to1]]=dis[to1],num[dep[to1]]=1;
                else if(dis[to1]==f[dep[to1]])num[dep[to1]]++;
                get_dep(to1,x);
            }
        }
    }
    void calc(int x)
    {
        int mlen=0;
        g[0]=0,num1[0]=1;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(!vis[to1])
            {
                num[1]=len=dep[to1]=1;dis[to1]=f[1]=e[i].val;get_dep(to1,0);
                for(int j=1;j<=len&&j<=K;j++)
                {
                    if(ans<f[j]+g[K-j])ans=f[j]+g[K-j],ans1=num[j]*num1[K-j];
                    else if(ans==f[j]+g[K-j])ans1+=num[j]*num1[K-j];
                }
                for(int j=1;j<=len&&j<=K;j++)
                {
                    if(g[j]<f[j])g[j]=f[j],num1[j]=num[j];
                    else if(g[j]==f[j])num1[j]+=num[j];
                }
                for(int j=1;j<=len&&j<=K;j++)f[j]=-1<<30,num[j]=0;
                mlen=max(mlen,len);
            }
        }
        for(int i=1;i<=mlen&&i<=K;i++)
        {
            g[i]=-1<<30;num1[i]=0;
        }
    }
    void dfs(int x)
    {
        vis[x]=1;
        calc(x);
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(!vis[to1])
            {
                sn=siz[to1];
                rot=0;get_root(to1,0);
                dfs(rot);
            }
        }
    }
    int main()
    {
        memset(head1,-1,sizeof(head1));
        memset(head,-1,sizeof(head));
        scanf("%d%d%d",&n,&m,&K);K--;
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add1(x,y,z);
            add1(y,x,z);
        }
        dijkstra();
        memset(vis,0,sizeof(vis));cnt=0;used[1]=1;build(1);//prin(1,0);
        memset(dis,0,sizeof(dis));memset(f,0xc0,sizeof(f));
        memset(g,0xc0,sizeof(g));g[0]=0,num1[0]=1;
        sn=n;mx[0]=1<<30;
        get_root(1,0);
        dfs(rot);
        printf("%d %d
    ",ans,ans1);
        return 0;
    }
    

    BZOJ4182: Shopping

    这道题非常的神啊,裸上树形DP是nm^2的,如果用二进制拆分的话,还要多一个log,不存在可过性,剪一剪枝能不能过不太清楚,不过看数据的样子,过的可能性不是很大,卡评测什么的可不好。

    可以看出,这又是一道有关路径信息的问题,这种情况下,我们可以想点分治能不能做。

    因为点分治其实是将树分成许多部分来处理,那么我们只需要知道每次的分治中心的最大值来更新答案就可以了。

    证明:如果一部分不经过分治中心,那么就一定在同一个子树中,那么最后一定会得到一个联通块满足这一部分经过它的分治中心。

    那么,我们就可以将问题转化为,给你一棵树,要求你求出经过根的一个联通块在满足题意取得最大值。这个就更加好想了一点,树形背包转化为dfs序+背包。状态不变,还是f[i][j]表示dfs序上第i个点,在i-n中选择了j个的最大值。

    我们考虑如果选择一个节点,那么必定会选择这个节点的父节点,那么,我们考虑,f[i][j]=f[i+1][j-c[i]]+w[i];那么如果我们不选择这个节点,就必定不会选择这个节点子树中的任何节点,也就是,f[i][j]=max(f[i][j],f[i+siz[i]][j]);

    附上代码:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <cstdlib>
    #include <set>
    #include <vector>
    using namespace std;
    #define N 505
    #define ll long long
    struct node
    {
        int to,next;
    }e[N<<1];
    int head[N],cnt,siz[N],vis[N],mx[N],f[N][4005],ans,w[N],c[N],d[N],n,m,rot,sn;
    void add(int x,int y)
    {
        e[cnt].to=y;
        e[cnt].next=head[x];
        head[x]=cnt++;
        return ;
    }
    void get_root(int x,int from)
    {
        siz[x]=1,mx[x]=0;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                get_root(to1,x);
                siz[x]+=siz[to1];
                mx[x]=max(mx[x],siz[to1]);
            }
        }
        mx[x]=max(mx[x],sn-siz[x]);
        if(mx[rot]>mx[x])rot=x;
    }
    int idx[N],tot,last[N];
    void get(int x,int from)
    {
        idx[++tot]=x;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(to1!=from&&!vis[to1])
            {
                get(to1,x);
            }
        }
        last[x]=tot;
    }
    void calc(int x)
    {
        tot=0;get(x,0);
        for(int i=1;i<=tot+1;i++)
        {
            for(int j=0;j<=m;j++)
            {
                f[i][j]=0;
            }
        }
        for(int i=tot;i;i--)
        {
            int t=d[idx[i]]-1;
            for(int j=m;j>=c[idx[i]];j--)
            {
                f[i][j]=f[i+1][j-c[idx[i]]]+w[idx[i]];
            }
            for(int j=1;j<=t;t-=j,j<<=1)
            {
                for(int k=m;k>=j*c[idx[i]];k--)
                {
                    f[i][k]=max(f[i][k],f[i][k-j*c[idx[i]]]+w[idx[i]]*j);
                }
            }
            if(t)
            {
                for(int j=m;j>=t*c[idx[i]];j--)
                {
                    f[i][j]=max(f[i][j],f[i][j-t*c[idx[i]]]+w[idx[i]]*t);
                }
            }
            for(int j=m;j>=0;j--)f[i][j]=max(f[i][j],f[last[idx[i]]+1][j]);
        }
        ans=max(ans,f[1][m]);
    }
    void dfs(int x)
    {
        vis[x]=1;
        calc(x);
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            int to1=e[i].to;
            if(!vis[to1])
            {
                sn=siz[to1];
                rot=0;
                get_root(to1,0);
                dfs(rot);
            }
        }
    }
    void init()
    {
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        cnt=0;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&w[i]);
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&c[i]);
            }
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&d[i]);
            }
            for(int i=1;i<n;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,y);
                add(y,x);
            }
            mx[0]=1<<30;rot=0;ans=0;sn=n;
            get_root(1,0);
            dfs(rot);
            printf("%d
    ",ans);
        }
        return 0;
    }
    

      先更新到这里...学完CDQ分治再更新

  • 相关阅读:
    05-----数据类型转换
    04-----赋值运算符
    03-----数据类型
    02-----第一个JavaScript代码
    Fxx and game
    Bomb
    Stammering Aliens
    DISUBSTR
    Life Forms
    后缀数组二·重复旋律2
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9093585.html
Copyright © 2011-2022 走看看