题意

https://codeforces.com/problemset/problem/526/G


 

思考

先考虑只有一次询问。如果我们选择了k条路径,那么就会有2k个叶子节点;反过来,如果选择了2k个叶子节点,总存在一种方案使得组成的k条路径形成一个联通块。因为若还没有连通块,总可以交换两条不交叉路径的端点,使他们交叉。

这样问题转化为:选k个从根节点(当让是询问的x为根)到叶子节点的路径,最大化经过的边权之和。这是一个经典的问题,可以按照长链剖分的思想,用堆来解决。

值得注意的是,第一次选择一定会到达树的直径的某个端点上。因此我们任选直径的某一个端点,让它作为树根。

预处理出所有k=1~n的答案。对于询问(u,k),若u已经在k答案的路径上了,直接输出;否则分三种情况考虑:

1.直径换一个端点,即在k答案的基础上塞进u子树中深度最大的叶子节点。作为补偿,找到u在k-1答案中第一次被选中的祖宗,减去两倍它的深度。

2.在k-1答案的基础上塞进u子树中深度最大的叶子节点。作为补偿,找到u在k-1答案中第一次被选中的祖宗,减去它的深度。

3.在k-1答案的基础上换一个儿子。

时间复杂度$O(nlogn)$


代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1E5+5;
  4 int n,m;
  5 int size,head[maxn*2];
  6 int lastans,root,now,dep[maxn],ans[maxn],son[maxn],fa[maxn][20],maxdep[maxn];
  7 int tot,vis[maxn];
  8 struct edge
  9 {
 10     int to,next,w;
 11 }E[maxn*2];
 12 struct node
 13 {
 14     int u,val;
 15     node(int a=0,int b=0)
 16     {
 17         u=a,val=b;
 18     }
 19     bool operator<(const node&A)const
 20     {
 21         return val<A.val; 
 22     }
 23 };
 24 priority_queue<node>Q; 
 25 inline void add(int u,int v,int w)
 26 {
 27     E[++size].to=v;
 28     E[size].next=head[u];
 29     E[size].w=w;
 30     head[u]=size;
 31 }
 32 void dfs(int u,int F,int d)
 33 {
 34     maxdep[u]=dep[u]=d;
 35     son[u]=u;
 36     if(d>now)
 37         root=u,now=d;
 38     for(int i=head[u];i;i=E[i].next)
 39     {
 40         int v=E[i].to;
 41         if(v==F)
 42             continue;
 43         dfs(v,u,d+E[i].w);
 44         if(maxdep[v]>maxdep[u])
 45             maxdep[u]=maxdep[v],son[u]=son[v];
 46     }
 47 }
 48 void initson(int u,int F,int d)
 49 {
 50     maxdep[u]=dep[u]=d;
 51     son[u]=u;
 52     for(int i=head[u];i;i=E[i].next)
 53     {
 54         int v=E[i].to;
 55         if(v==F)
 56             continue;
 57         initson(v,u,d+E[i].w);
 58         if(maxdep[v]>maxdep[u])
 59             maxdep[u]=maxdep[v],son[u]=v;
 60     }
 61 }
 62 void get(int u,int F,int d)
 63 {
 64     if(son[u]==u)
 65         Q.push(node(u,d));
 66     fa[u][0]=F;
 67     for(int i=1;i<20;++i)
 68         fa[u][i]=fa[fa[u][i-1]][i-1];
 69     for(int i=head[u];i;i=E[i].next)
 70     {
 71         int v=E[i].to;
 72         if(v==F)
 73             continue;
 74         else if(v==son[u])
 75             get(v,u,d+E[i].w);
 76         else
 77             get(v,u,E[i].w);
 78     }
 79 }
 80 void init()
 81 {
 82     initson(root,root,0);
 83     get(root,root,0);
 84     while(!Q.empty())
 85     {
 86         node A=Q.top();
 87         Q.pop();
 88         ++tot;
 89         ans[tot]=ans[tot-1]+A.val;
 90         for(int u=A.u;!vis[u];u=fa[u][0])
 91             vis[u]=tot;
 92     }
 93 }
 94 inline int solve(int u,int k)
 95 {
 96     k=min(k,tot);
 97     if(vis[u]<=k)
 98         return ans[k];
 99     int F=u;
100     for(int i=19;i>=0;--i)
101         if(vis[fa[F][i]]>k)
102             F=fa[F][i];
103     F=fa[F][0];
104     return max(ans[k]+maxdep[u]-2*dep[F],max(
105                maxdep[u]-dep[F]+ans[k-1],
106                ans[k]+maxdep[u]-maxdep[F]));
107 } 
108 int main()
109 {
110     ios::sync_with_stdio(false);
111     cin>>n>>m;
112     for(int i=2;i<=n;++i)
113     {
114         int x,y,z;
115         cin>>x>>y>>z;
116         add(x,y,z);
117         add(y,x,z);
118     }
119     dfs(1,1,0);
120     now=0;
121     dfs(root,root,now);
122     init();
123     while(m--)
124     {
125         int x,y;
126         cin>>x>>y;
127         x=(x+lastans-1)%n+1;
128         y=(y+lastans-1)%n+1;
129         lastans=solve(x,y*2-1);
130         cout<<lastans<<endl;
131     }
132     return 0;
133 }
View Code

 

 posted on 2019-08-27 09:43  GreenDuck  阅读(317)  评论(0编辑  收藏  举报