zoukankan      html  css  js  c++  java
  • 【BZOJ1984】月下“毛景树”-树链剖分

    题目大意:有一棵树有N个点,每条边有边权,有4种操作:1.Change i w:将输入的第i条边的权值修改为w。2.Cover u v w:将点u和点v之间路径上的边权都修改为w。3.Add u v w:将点u和点v之间路径上的边权都加上w。4.Max u v:询问点u和点v之间路径上边权的最大值。对于每个询问,给出正确的答案。

    做法:由于有多种操作,而且有两个区间修改的操作,所以需要两个lazytag:add(Add操作的标记,表示当前区间的数全部加上了add这个值)和cov(Cover操作的标记,表示当前区间的数都为cov这个值)。需要注意的是,这两个lazytag不能同时起效,否则会导致奇怪的错误......在Add操作中,如果当前区间被操作区间完全包含,且当前区间的cov标记不为-1(即有效),则直接将值加进cov中,否则将值加进add中。在Cover操作中,如果当前区间被操作区间完全包含,则把当前区间的add标记归零,将cov改成要修改成的值。具体的步骤见代码。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #define inf 999999999
    using namespace std;
    int t,n,tot,f[100010],siz[100010],dep[100010],pos[100010],p,a,b,c;
    int d[100010][3],first[100010],son[100010],top[100010],root;
    int qpos[100010];
    char op[10];
    struct edge
    {
      int v,next;
    }e[20010];
    int seg[400010],segp[400010],cov[400010]; //segp为add标记,cov为cov标记,seg记录区间最大值
    
    void readin(int a,int b,int c)
    {
      e[++tot].v=b;
      e[tot].next=first[a];
      first[a]=tot;
    }
    
    void dfs1(int now)
    {
      siz[now]=1;son[now]=0;
      for(int i=first[now];i>0;i=e[i].next)
        if (e[i].v!=f[now])
    	{
    	  dep[e[i].v]=dep[now]+1;
    	  f[e[i].v]=now;
    	  dfs1(e[i].v);
    	  siz[now]+=siz[e[i].v];
    	  if (siz[e[i].v]>siz[son[now]]) son[now]=e[i].v;
    	}
    }
    
    void dfs2(int now,int chain)
    {
      pos[now]=++p;top[now]=chain;
      if (son[now]) dfs2(son[now],chain);
      for(int i=first[now];i>0;i=e[i].next)
        if (e[i].v!=f[now]&&e[i].v!=son[now])
    	  dfs2(e[i].v,e[i].v);
    }
    
    void pushdown(int no)
    {
      if (cov[no]!=-1)
      {
    	cov[no<<1]=cov[(no<<1)+1]=cov[no];
    	seg[no<<1]=seg[(no<<1)+1]=cov[no];
    	segp[no<<1]=segp[(no<<1)+1]=0;
    	cov[no]=-1;
      }
      if (segp[no]!=0)
      {
        seg[no<<1]+=segp[no];seg[(no<<1)+1]+=segp[no];
        if (cov[no<<1]==-1) segp[no<<1]+=segp[no];
    	else cov[no<<1]+=segp[no];
    	if (cov[(no<<1)+1]==-1) segp[(no<<1)+1]+=segp[no];
    	else cov[(no<<1)+1]+=segp[no];
    	segp[no]=0;
      }
    }
    
    void pushup(int no)
    {
      seg[no]=max(seg[no<<1],seg[(no<<1)+1]);
    }
    
    void buildtree(int no,int l,int r)
    {
      int mid=(l+r)>>1;
      segp[no]=0;cov[no]=-1;
      if (l==r) {seg[no]=d[qpos[l]][2];return;}
      buildtree(no<<1,l,mid);
      buildtree((no<<1)+1,mid+1,r);
      pushup(no);
    }
    
    void change(int no,int l,int r,int a,int c)
    {
      int mid=(l+r)>>1;
      if (l==r) {seg[no]=c;return;}
      pushdown(no);
      if (a<=mid) change(no<<1,l,mid,a,c);
      else change((no<<1)+1,mid+1,r,a,c);
      pushup(no);
    }
    
    void segadd(int no,int l,int r,int s,int t,int w)
    {
      int mid=(l+r)>>1;
      if (l>=s&&r<=t)
      {
        if (cov[no]==-1) segp[no]+=w;
    	else {cov[no]+=w;segp[no]=0;}
    	seg[no]+=w;
    	return;
      }
      pushdown(no);
      if (s<=mid) segadd(no<<1,l,mid,s,t,w);
      if (t>mid) segadd((no<<1)+1,mid+1,r,s,t,w);
      pushup(no);
    }
    
    void segcov(int no,int l,int r,int s,int t,int w)
    {
      int mid=(l+r)>>1;
      if (l>=s&&r<=t)
      {
        if (segp[no]) segp[no]=0;
    	seg[no]=w;
    	cov[no]=w;
    	return;
      }
      pushdown(no);
      if (s<=mid) segcov(no<<1,l,mid,s,t,w);
      if (t>mid) segcov((no<<1)+1,mid+1,r,s,t,w);
      pushup(no);
    }
    
    int querymx(int no,int l,int r,int s,int t)
    {
      int mid=(l+r)>>1;
      if (l>=s&&r<=t) return seg[no];
      int mx=-inf;
      pushdown(no);
      if (s<=mid) mx=max(mx,querymx(no<<1,l,mid,s,t));
      if (t>mid) mx=max(mx,querymx((no<<1)+1,mid+1,r,s,t));
      pushup(no);
      return mx;
    }
    
    int query(int a,int b)
    {
      int mx=-inf;
      while(top[a]!=top[b])
      {
        if (dep[top[a]]<dep[top[b]]) swap(a,b);
    	mx=max(mx,querymx(1,1,p,pos[top[a]],pos[a]));
    	a=f[top[a]];
      }
      if (dep[a]<dep[b]) swap(a,b);
      if (a!=b) mx=max(mx,querymx(1,1,p,pos[son[b]],pos[a]));
      return mx;
    }
    
    void add(int a,int b,int w)
    {
      while(top[a]!=top[b])
      {
        if (dep[top[a]]<dep[top[b]]) swap(a,b);
    	segadd(1,1,p,pos[top[a]],pos[a],w);
    	a=f[top[a]];
      }
      if (dep[a]<dep[b]) swap(a,b);
      if (a!=b) segadd(1,1,p,pos[son[b]],pos[a],w);
    }
    
    void cover(int a,int b,int w)
    {
      while(top[a]!=top[b])
      {
        if (dep[top[a]]<dep[top[b]]) swap(a,b);
    	segcov(1,1,p,pos[top[a]],pos[a],w);
    	a=f[top[a]];
      }
      if (dep[a]<dep[b]) swap(a,b);
      if (a!=b) segcov(1,1,p,pos[son[b]],pos[a],w);
    }
    
    void read()
    {
      op[0]=' ';
      while (op[0]<'A'||op[0]>'Z') scanf("%s",op);
    }
    
    void input()
    {
      scanf("%d",&n);
      root=1;
      memset(first,0,sizeof(first));
      memset(seg,0,sizeof(seg));
      tot=f[root]=dep[root]=p=0;
      for(int i=1;i<=n-1;i++)
      {
        scanf("%d %d %d",&a,&b,&c);
    	d[i][0]=a;d[i][1]=b;d[i][2]=c;
    	readin(a,b,c);readin(b,a,c);
      }
      dfs1(root);
      dfs2(root,root);
      for(int i=1;i<n;i++)
      {
    	if (dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);
    	qpos[pos[d[i][1]]]=i;
      }
      buildtree(1,1,p);
    }
    
    void work()
    {
      int a,b;
      for(read();op[0]!='S';read())
      {
        int w;
        scanf("%d %d",&a,&b);
        if (op[0]=='M') printf("%d
    ",query(a,b));
    	else if (op[0]=='A') {scanf("%d",&w);add(a,b,w);}
             else
    		 {
    		   if (op[1]=='h') change(1,1,p,pos[d[a][1]],b);
    		   else {scanf("%d",&w);cover(a,b,w);}
    		 }
      }
    }
    
    int main()
    {
      input();
      work();
      
      return 0;
    }
    


  • 相关阅读:
    Codeforces 992C(数学)
    Codeforces 990C (思维)
    Codeforces 989C (构造)
    POJ 1511 Invitation Cards(链式前向星,dij,反向建边)
    Codeforces 1335E2 Three Blocks Palindrome (hard version)(暴力)
    POJ 3273 Monthly Expense(二分)
    POJ 2566 Bound Found(尺取前缀和)
    POJ 1321 棋盘问题(dfs)
    HDU 1506 Largest Rectangle in a Histogram(单调栈)
    POJ 2823 Sliding Window(单调队列)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793952.html
Copyright © 2011-2022 走看看