【BZOJ4519】【Sdoi2016】游戏 线段树

来源:互联网 发布:美国大律师 知乎 编辑:程序博客网 时间:2024/04/30 04:49

第一次接触到这么神奇的线段树。

首先树的形态不改变所以数链剖分+线段树建树。对于线段树上的每一个点,我们保证其最多保存一条直线,如果存在第二条直线,那么两条直线“占据空间”较小的一个一定可以下传到它的某个儿子,而这个节点只存占据空间较大的一个即可。

查询的时候要用到永久化(好像是叫这个奇怪的名字)思想,一边向下查一边比较存放在当前节点的直线能否更新最小值。

 

/**************************************************************     Problem: 4515     User: RicardoWang     Language: C++     Result: Accepted     Time:21920 ms     Memory:38232 kb ****************************************************************/  #include<cstdlib> #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; #define oo 123456789123456789ll #define maxn 200005 void _read(int &x){x=0; char ch=getchar(); bool flag=false;while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}if(flag)x=-x; return ;} void _readLL(long long &x){x=0; char ch=getchar(); bool flag=false;while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}if(flag)x=-x; return ;}   struct edge{int to,d,next;}e[maxn*2]; int edge_ct,head[maxn]; void add(int x,int y,int z){e[++edge_ct]=(edge){y,z,head[x]};head[x]=edge_ct;e[++edge_ct]=(edge){x,z,head[y]};head[y]=edge_ct;} int n,m,son[maxn],sz[maxn],d[maxn],tp[maxn],tr[maxn],f[maxn],_time,_tr[maxn],fd[maxn]; long long dis[maxn]; void DFS_1(int now,int fa) {     sz[now]=1; son[now]=0; d[now]=d[fa]+1; f[now]=fa; dis[now]=dis[fa]+fd[now];     for(int id=head[now];id;id=e[id].next){if(e[id].to==fa)continue;fd[e[id].to]=e[id].d;DFS_1(e[id].to,now);sz[now]+=sz[e[id].to];if(sz[e[id].to]>sz[son[now]])son[now]=e[id].to;} return ; } void DFS_2(int now,int top) {     tr[now]=++_time;tp[now]=top; if(son[now])DFS_2(son[now],top);     for(int id=head[now];id;id=e[id].next){if(e[id].to==f[now] || e[id].to==son[now])continue; DFS_2(e[id].to,e[id].to);}return ; } void Init(){int x,y,z;_read(n);_read(m);for(int i=1;i<n;i++){_read(x);_read(y);_read(z);add(x,y,z);}DFS_1(1,0);DFS_2(1,1);return ;} int np,rt,chi[2*maxn][2];bool tag[maxn*2]; long long d_first[2*maxn],dsum[2*maxn],minv[maxn]; void build(int &now,int L,int R){now=++np; tag[now]=false; minv[now]=oo;if(L==R){d_first[now]=dsum[now]=fd[_tr[L]];return;}int m=(L+R)>>1;build(chi[now][0],L,m);build(chi[now][1],m+1,R);d_first[now]=d_first[chi[now][0]];dsum[now]=dsum[chi[now][0]]+dsum[chi[now][1]];} int LCA(int x,int y){   while(tp[x]!=tp[y]){if(d[tp[x]]>=d[tp[y]])x=f[tp[x]];else y=f[tp[y]];} return d[x]>d[y] ? y:x;} long long getsum(int now,int L,int R,int x,int y) {     if(x<=L && R<=y)return dsum[now];     long long t1=0,t2=0;    int m=(L+R)>>1;     if(x<=m)t1=getsum(chi[now][0],L,m,x,y);     if(y>m)t2=getsum(chi[now][1],m+1,R,x,y);     return t1+t2; } long long _A[maxn*2],_B[maxn*2]; void pushtag(int now,int L,int R,long long A,long long B) {     if(!tag[now]){  tag[now]=true; _A[now]=A; _B[now]=B ;}     else    {         if(A==_A[now])         {             _B[now]=min(_B[now],B);         }         else        {             if(A>_A[now]){swap(A,_A[now]);swap(B,_B[now]);}             long long T=(B-_B[now])/(_A[now]-A);             while(T*(_A[now]-A)<=(B-_B[now]))T++;             if(T<=d_first[now])             {                 _A[now]=A; _B[now]=B;             }             else if(T>dsum[now])             {                               }             else            {                 if(T<=dsum[chi[now][0]])                 {                     pushtag(chi[now][0],L,(L+R)/2,_A[now],_B[now]);                     _A[now]=A; _B[now]=B;                 }                 else                {                     pushtag(chi[now][1],(L+R)/2+1,R,A,B+A*dsum[chi[now][0]]);                 }             }         }     }     return ; } long long update(int now,int L,int R,int x,int y,long long A,long long B) {        if(x<=L && R<=y)     {         pushtag(now,L,R,A,B);         minv[now]=min(minv[now],A>=0 ? A*d_first[now]+B : A*dsum[now]+B);         return dsum[now];     }     int m=(L+R)>>1; long long tmp=0;     if(x<=m)tmp=update(chi[now][0],L,m,x,y,A,B);     if(y>m)tmp=tmp+update(chi[now][1],m+1,R,x,y,A,B+tmp*A);     minv[now]=min(minv[now],min(minv[chi[now][0]],minv[chi[now][1]]));     return tmp; } long long get(int now,int L,int R,int x) {     if(!tag[now])return oo;     else return _A[now]*getsum(rt,1,n,L,x)+_B[now]; } long long query(int now,int L,int R,int x,int y) {     long long ans=oo;     if(tag[now] && x<=R && y>=L)ans=min(ans,_A[now]>=0? get(now,L,R,max(x,L)):get(now,L,R,min(y,R)));     if(x<=L && R<=y)     {         return min(ans,minv[now]);     }     int m=(L+R)>>1;     if(x<=m)ans=min(ans,query(chi[now][0],L,m,x,y));     if(y>m)ans=min(ans,query(chi[now][1],m+1,R,x,y));     return ans; } void op1(int x,int y,long long a,long long b) {     int z=LCA(x,y);     long long dissum=0;     while(tp[x]!=tp[z])     {         dissum+=getsum(rt,1,n,tr[tp[x]],tr[x]);         update(rt,1,n,tr[tp[x]],tr[x],-a,dissum*a+b);                x=f[tp[x]];     }     dissum+=getsum(rt,1,n,tr[z],tr[x]);      update(rt,1,n,tr[z],tr[x],-a,dissum*a+b);     dissum-=fd[z];     dissum+=dis[y]-dis[z];     while(tp[y]!=tp[z])     {         dissum-=getsum(rt,1,n,tr[tp[y]],tr[y]);         update(rt,1,n,tr[tp[y]],tr[y],a,dissum*a+b);         y=f[tp[y]];     }     if(y!=z){dissum-=getsum(rt,1,n,tr[son[z]],tr[y]);update(rt,1,n,tr[son[z]],tr[y],a,dissum*a+b);}     return ; } char s[35];int cc; void out(long long x) {     if(!x)putchar('0');     if(x<0){x=-x;putchar('-');}     cc=0; while(x){s[++cc]=x%10+'0'; x=x/10;}     while(cc){putchar(s[cc]);cc--;}     putchar('\n');     return ; } void op2(int x,int y) {     int z=LCA(x,y);     long long ans=oo;     while(tp[x]!=tp[z])     {         ans=min(ans,query(rt,1,n,tr[tp[x]],tr[x])); x=f[tp[x]];     }     ans=min(ans,query(rt,1,n,tr[z],tr[x]));     while(tp[y]!=tp[z])     {         ans=min(ans,query(rt,1,n,tr[tp[y]],tr[y])); y=f[tp[y]];     }     ans=min(ans,query(rt,1,n,tr[z],tr[y]));     out(ans);     return ; } void work() {     for(int i=1;i<=n;i++)_tr[tr[i]]=i;     build(rt,1,n);     char op;int s,t;long long a,b;     int cct=0;     for(int i=1;i<=m;i++)     {         op=getchar(); while(op!='1'&&op!='2')op=getchar();         if(op=='1')         {             if(i==2458)             {                 int hh;                 hh++;             }             _read(s); _read(t); _readLL(a); _readLL(b); op1(s,t,a,b);         }         else        {             cct++;             if(i==2459)             {                 int hh;                 hh++;             }             _read(s); _read(t);/* s=110;t=110;printf("%d ",i);*/op2(s,t);         }     }     return ; } int main() {     //freopen("in.txt","r",stdin);     //freopen("out.txt","w",stdout);     Init();     work();     return 0; }

0 0
原创粉丝点击