标签:转化 main lap 思考 ide 输出 时间 turn ios
题意
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 }
标签:转化 main lap 思考 ide 输出 时间 turn ios
原文地址:https://www.cnblogs.com/GreenDuck/p/11416407.html