zoukankan      html  css  js  c++  java
  • CF526G Spiders Evil Plan

    cf

    经过一番思考,可以发现原问题等价于选出(2y)个叶子,使得他们两两之间路径的并包含(x)且边权和最大(如果(2yge)总叶子个数则直接输出所有边权值之和).这是因为你可以通过让(2y)个叶子两两匹配得到(y)条路径,然后(y)条路径的并也就是这些叶子两两之间路径的并

    先考虑暴力(?),对于一个(x)依次算出(y=1,2,3...)的答案.(y=1)时,答案就是把(x)作为根时,最大的 两个不同子树到根的最长链之和的.可以发现这两条最长链中有一条的端点一定是树直径的两端点之一,并且这条链一定经过直径的中点.如果我们把树的根改为树直径的中点,那么询问((x,1))的答案就是(x)到直径两端点的距离最大值加(x)子树内到根最长链长度

    然后考虑(y)每次加(1),贪心的考虑就是每次选出两个叶子使得路径并的增加量最大.由于每次选的叶子都是使得答案增量最大的,且选完后会使得一些其他叶子的贡献减少,如果我们对于 删去(y=1)时选的链剩下的树 做长链剖分,可以发现每次选的叶子代表的都是剩余的最长的长链,所以对于(x),只要把所有长链长度丢进一个线段树,就可以通过线段树二分的手段求出前(k)大的长度之和

    每次长链剖分是不行的.这里我们先对以直径中点为根的树长链剖分,然后考虑其他的点.一个点(x)会先删掉(y=1)时的链,这条不在长链集合中的链一定是原来若干条长链的前缀+(x)所在长链+直径对应两个长链之一.我们dfs整棵树,如果点(x)和父亲在一条长链上,那么他们对应长链集合不变,否则会加入父亲长链剩余的下半部分,以及删去(x)所在长链,所以这里可以使用可持久化线段树来维护

    #include<bits/stdc++.h>
    #define LL long long
    #define db long double
    
    using namespace std;
    const int N=1e5+10,mod=998244353;
    int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[N<<1],nt[N<<1],w[N<<1],hd[N],tot=1;
    void adde(int x,int y,int z)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
    }
    int s1[N*70],s2[N*70],ch[N*70][2],rt[N],tt,vl=1,vr=1e8;
    void inst(int o1,int o2,int x,int dx)
    {
        s1[o1]=s1[o2]+dx,s2[o1]=s2[o2]+x*dx;
        int l=vl,r=vr;
        while(l<r)
        {
        	int mid=(l+r)>>1;
        	if(x<=mid)
        	{
        	    ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];
        	    o1=ch[o1][0],o2=ch[o2][0];
        	    r=mid;
        	}
        	else
        	{
        	    ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;
        	    o1=ch[o1][1],o2=ch[o2][1];
        	    l=mid+1;
        	}
    	s1[o1]=s1[o2]+dx,s2[o1]=s2[o2]+x*dx;
        }
    }
    int a1,a2;
    int q1(int o,int l,int r,int k)
    {
        if(l==r) return l;
        int mid=(l+r)>>1;
        if(s1[ch[o][1]]<k)
        {
        	a1+=s1[ch[o][1]],a2+=s2[ch[o][1]];
        	return q1(ch[o][0],l,mid,k-s1[ch[o][1]]);
        }
        else return q1(ch[o][1],mid+1,r,k);
    }
    int n,q,dt[N],r1,r2,fa[N],fw[N],de[N],dp[N],hs[N],top[N],zl[N],fy;
    void dfs0(int x)
    {
        dt[x]=max(dt[x],de[x]);
        if(de[r1]<de[x]) r1=x;
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
        	if(y==fa[x]) continue;
        	fa[y]=x,de[y]=de[x]+w[i],dfs0(y);
        }
    }
    void dfs1(int x)
    {
        dp[x]=de[x];
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(y==fa[x]) continue;
            fa[y]=x,fw[y]=w[i],de[y]=de[x]+w[i],dfs1(y);
            if(dp[y]>dp[x]) dp[x]=dp[y],hs[x]=y;
        }
    }
    void dfs2(int x)
    {
        if(hs[x]) top[hs[x]]=top[x],dfs2(hs[x]);
        for(int i=hd[x];i;i=nt[i])
        {
    	    int y=to[i];
    	    if(y==fa[x]||y==hs[x]) continue;
        	top[y]=y,dfs2(y);
        }
    }
    void dfs3(int x)
    {
        for(int i=hd[x];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==fa[x]) continue;
        	rt[y]=rt[x];
        	if(y!=hs[x])
        	{
        	    int las=rt[y];
        	    inst(rt[y]=++tt,las,x==r1?zl[fy]:dp[x]-de[x],1);
        	    las=rt[y];
        	    inst(rt[y]=++tt,las,zl[y],-1);
        	}
        	dfs3(y);
        }
    }
    
    int main()
    {
        //////
        n=rd(),q=rd();
        for(int i=1;i<n;++i)
        {
            int x=rd(),y=rd(),z=rd();
        	adde(x,y,z);
        }
        dfs0(1);
        r2=r1,r1=0,fa[r2]=de[r2]=0,dfs0(r2);
        r2=r1,r1=0,fa[r2]=de[r2]=0,dfs0(r2);
        int nl=de[r1];
        while(fa[r1]!=r2&&de[r1]>nl-de[r1]) r1=fa[r1];
        fa[r1]=de[r1]=0;
        dfs1(r1),top[r1]=r1,dfs2(r1);
        for(int i=1;i<=n;++i)
    	if(top[i]==i)
    	{
    	    int las=rt[0];
    	    inst(rt[0]=++tt,las,zl[i]=dp[i]-de[i]+fw[i],1);
    	}
        int nm=s1[rt[0]],zans=s2[rt[0]],las;
        inst(rt[r1]=++tt,rt[0],zl[r1],-1),dt[r1]=nl;
        las=rt[r1],inst(rt[r1]=++tt,las,nl-zl[r1],-1);
        for(int i=1;i<=n;++i)
    	if(i!=r1) dt[i]+=dp[i]-de[i];
        for(int i=hd[r1];i;i=nt[i])
        {
        	int y=to[i];
        	if(y==hs[r1]) continue;
        	fy=dp[fy]>dp[y]?fy:y;
        }
        dfs3(r1);
        int ans=0;
        while(q--)
        {
        	int x=(rd()+ans-1)%n+1,y=((rd()+ans-1)%n+1)*2;
        	if(y>=nm) ans=zans;
        	else
        	{
        	    y-=2,ans=dt[x];
        	    a1=a2=0;
        	    int nv=q1(rt[x],vl,vr,y);
        	    ans+=a2+(y-a1)*nv;
        	}
        	printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    安装完QQ必须要删除掉的几个恐怖文件
    dede实战系统:更换成kindEditor编辑器
    PHP 5.4 中经 htmlspecialchars 转义后的中文字符串为空的问题
    DEDECMS图片集上传图片出错302的解决办法
    dedecms安装完成后登录后台出现空白
    OFV.msi是什么 为什么更新时无法安装
    CentOS 挂载NTFS分区的两种方法
    centos使用yum安装gcc
    NetBeans菜单栏字体太小了
    注入漏洞页
  • 原文地址:https://www.cnblogs.com/smyjr/p/12558655.html
Copyright © 2011-2022 走看看