WOJ 651 离线LCA+链上修改+静态查询(树上前缀和?)

来源:互联网 发布:淘宝秒杀技巧软件 编辑:程序博客网 时间:2024/06/04 22:06

651. The Highest Peak


Time Limit: 2 second

Long long ago, Wuhan University locates a plain with the same height. There areNNN points in WHU which are connected by N−1N-1N1 edges (just like a tree) and their initial height is 0 meters. Now we want to heap up sail on the points to form peaks and you should answer the number and the height of the highest peak.

Input

First line is NNN and KKK, the number of the points and the number of actions to head up. (0<N,K≤5×1050 < N, K \le 5\times 10^50<N,K5×105)

Next N−1N-1N1 lines includes two numbers XXX and YYY, meaning that the point XXX and point YYY are connected directly. (0<X,Y≤N0 < X, Y \le N0<X,YN)

In the following KKK lines, each line consists of three integers X,Y,HX, Y, HX,Y,H, means that we will heap up HHH meters high soil in every points belonging to the path from XXX to YYY(X≠Y,0<X,Y≤N,0≤H≤109X\neq Y, 0 < X, Y \le N, 0 \le H \le 10^9XY,0<X,YN,0H109).

Output

The number and the height of the highest peak (if there are servel highest peaks, select the one who has the smallest number).

Examples

Input 1

5 41 21 32 43 51 2 53 5 64 5 91 5 1

Output 1

3 16

Source

第六届华中区程序设计邀请赛暨武汉大学第十五届校赛



        看完题,有点数据结构基础的人就会知道,这不就是裸的树链剖分吗(我也是这么认为的)。然后你或许就会开始敲模板,然后你就进了出题人的陷阱……

        很显然,虽说考数据结构的题一般都是套模板,但是也不会有这题这么好的事情。出题人心思就是要卡log,那你也没什么办法。当时我在现场由于前面的题做得比较懊恼,然后心想这题这么裸,没仔细考虑就直接敲了LCT(大材小用,因为我对这个更熟悉),结果当然直接是tle了。T_T!结束前也想到了可能数据刁钻,但是我之前还没讲过卡log的题,没有应付经验……

        既然卡log,那我们只能换一种思路了。赛后,聪神和我说了一下又有那种恍然大悟的感受。例如,对于(x,y)的链,我们在x处、y处打上+w的标记,在他们的lca和lca的父亲打上-w的标记。然后,在用一种应该是叫树上前缀和的东西维护每一个点的权值。很熟悉吧,和普通的区间前缀和一样,对于某个区间(l,r),只需要在两个端点一处加,一处减,再求前缀和就能单点查询。只不过这题把一维的东西搬到了树上而已。任何一个点的权值,等于其所有子孙辈的和。在x处打标记,则表示从x点一直往上到根所有点权值增加,在y处也是如此。那么在lca这个点就重复加了,于是lca处减一次。lca的父亲以上不在链中,故还要在lca的父亲那减一次。

        对于每一个操作,先离线保存下来,离线LCA处理出所有操作的两点的lca。按照之前说的那样处理每一个修改后,求一次树上前缀和,在找最大值即可。具体代码如下:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstdlib>#include<cmath>#include<cstring>#include<iomanip>#define LL long long#define MAX_V 500100#define MAX_INT 2147483647using namespace std;struct edge{int x,y,next;} g[MAX_V*2];struct node{int x,y,w,next,lca;} q[MAX_V*2];int f[MAX_V],ls[MAX_V],lq[MAX_V],fa[MAX_V];long long sum[MAX_V];int n,m,s,e,p;bool vv[MAX_V];int find(int x){if (f[x]==x) return x;f[x]=find(f[x]);return f[x];}inline void addq(int x,int y,int w){q[++p].x=x;q[p].y=y;q[p].w=w;q[p].next=lq[x];lq[x]=p;q[++p].y=x;q[p].x=y;q[p].w=w;q[p].next=lq[y];lq[y]=p;}inline void add(int x,int y){g[++e].x=x;g[e].y=y;g[e].next=ls[x];ls[x]=e;}inline void lca(int s){f[s]=s;int i=ls[s];while (i>0){if (g[i].y!=fa[s]){fa[g[i].y]=s;lca(g[i].y);f[find(g[i].y)]=find(s);} i=g[i].next;}vv[s]=1;i=lq[s];while (i>0){if (vv[q[i].y]) q[i].lca=f[find(q[i].y)];i=q[i].next;}}inline void dp(int dep){int i=ls[dep];while (i>0){if (g[i].y!=fa[dep]){dp(g[i].y);sum[dep]+=sum[g[i].y];} i=g[i].next;}}int main(){cin>>n>>m;for(int i=1;i<n;i++){int x,y; scanf("%d%d",&x,&y);add(x,y); add(y,x);}for(int i=1;i<=m;i++){int x,y,w; scanf("%d%d%d",&x,&y,&w);addq(x,y,w);}lca(1);for(int i=1;i<=p;i+=2){int lca=max(q[i].lca,q[i+1].lca);sum[q[i].x]+=q[i].w;sum[q[i].y]+=q[i].w;sum[lca]-=q[i].w;sum[fa[lca]]-=q[i].w;}dp(1);int ans=1;for(int i=2;i<=n;i++)if (sum[i]>sum[ans]) ans=i;printf("%d %lld\n",ans,sum[ans]);return 0;}

        这个离线LCA的tarjan模板已经很老了,应该是高中OI时代的模板,虽然旧,用的还是人工的边表,但是速度却是很快的。记得好像是仿照LRJ黑书的染色的方法写的。

0 0
原创粉丝点击