• [bzoj2157/lgoj1505]旅游


    题目大意:

    直接传送门:

    luogu

    bzoj

    题解

    树剖毒瘤题。

    若您不会树剖,可以看yzhang神仙的讲解

    这是一道很有技巧性的树剖题:

    1. 边权 v.s. 点权:
      这道题乍一看和往常的树剖不一样:权值在边上而不在点上

      这时候我们应该对树进行一些转化,

      先让其变为一颗有根树,

      让每一个边和儿子一一对应。

      如图所示:


      还有一点要注意,
      例如求这一条红色链的权值:

      黄色的点是对应的点,不能将绿点(即\(lca\))算进去

    2. 线段树取负操作时,最大值和最小值互换在取负。标记为取负标记。

      代码如下所示:

      #include<bits/stdc++.h>
      #define mp make_pair
      #define pb push_back
      
      #define lson(id) (id<<1)
      #define rson(id) (id<<1|1)
      
      using namespace std;
      typedef long long ll;
      typedef unsigned long long ull;
      typedef vector<int > vi;
      typedef pair<int ,int > pii;
      typedef vector<pii> vii;
      const int inf=2e9, maxn=40007, mod=1e9+7;
      const ll linf=0x3f3f3f3f3f3f3f3fLL;
      const ll P=19260817;
      int n;
      struct edge{
          int v,nxt,val;
      }e[maxn<<1];
      int head[maxn],tot;
      inline void addedge(int u,int v,int val){
          e[++tot].v=v;
          e[tot].val=val;
          e[tot].nxt=head[u];
          head[u]=tot;
      }
      int son[maxn],top[maxn],w[maxn],size[maxn],fa[maxn],dep[maxn],num[maxn],a[maxn];
      int cnt=0;
      void dfs1(int u,int f){
          dep[u]=dep[f]+1;
          fa[u]=f;
          size[u]=1;
          for(int i=head[u];i;i=e[i].nxt){
              int v=e[i].v;
              if(v==f)continue;
              w[v]=e[i].val;
              dfs1(v,u);
              size[u]+=size[v];
              if(son[u]==0||size[v]>size[son[u]])son[u]=v;
          }
      }
      void dfs2(int u,int t){
          top[u]=t;
          num[u]=++cnt;a[cnt]=w[u];
          if(son[u])dfs2(son[u],t);
          for(int i=head[u];i;i=e[i].nxt){
              int v=e[i].v;
              if(v==son[u]||v==fa[u])continue;
              dfs2(v,v);
          }
      } 
      struct treeNode{
          int sum,Min,Max;
      }tree[maxn<<2];
      int lazy[maxn<<2];
      void pushUp(int id){
          tree[id].sum=tree[lson(id)].sum+tree[rson(id)].sum;
          tree[id].Max=max(tree[lson(id)].Max,tree[rson(id)].Max);
          tree[id].Min=min(tree[lson(id)].Min,tree[rson(id)].Min);
      }
      void change(int id){
          tree[id].sum= -(tree[id].sum);
          int Maxa=tree[id].Max,Mina=tree[id].Min;
          tree[id].Max=-Mina,tree[id].Min=-Maxa;
          lazy[id]^=1;
      }
      void pushDown(int id){
          if(lazy[id]){
              change(lson(id)),change(rson(id));
              lazy[id]=0;
          }
      }
      void build(int id,int l,int r){
          if(l==r){
              tree[id].sum=tree[id].Max=tree[id].Min=a[l];
              return;
          }
          int mid=(l+r)>>1;
          build(lson(id),l,mid);
          build(rson(id),mid+1,r);
          pushUp(id);
      }
      void modify(int id,int l,int r,int pos,int val){
          if(l==r){
              tree[id].sum=tree[id].Max=tree[id].Min=val;
              return ;
          }
          pushDown(id);
          int mid=(l+r)>>1;
          if(pos<=mid)modify(lson(id),l,mid,pos,val);
          else modify(rson(id),mid+1,r,pos,val);
          pushUp(id);
      }
      void update(int id,int l,int r,int L,int R){
          if(L<=l&&r<=R){
              change(id);
              return ;
          }
          pushDown(id);
          int mid=(l+r)>>1;
          if(L<=mid)update(lson(id),  l  ,mid,L,R);
          if(R>mid) update(rson(id),mid+1, r ,L,R);
          pushUp(id);
      }
      int querySum(int id,int l,int r,int L,int R){
          if(L<=l&&r<=R){
              return tree[id].sum;
          }
          pushDown(id);
          int mid=(l+r)>>1;
          int ans=0;
          if(L<=mid)ans+=querySum(lson(id),l,mid,L,R);
          if(R>mid)ans+=querySum(rson(id),mid+1,r,L,R);
          return ans;
      }
      int queryMax(int id,int l,int r,int L,int R){
          if(L<=l&&r<=R){
              return tree[id].Max;
          }
          pushDown(id);
          int mid=(l+r)>>1;
          int ans=-inf;
          if(L<=mid)ans=max(ans,queryMax(lson(id),l,mid,L,R));
          if(R>mid)ans=max(ans,queryMax(rson(id),mid+1,r,L,R));
          return ans;
      }
      int queryMin(int id,int l,int r,int L,int R){
          if(L<=l&&r<=R){
              return tree[id].Min;
          }
          pushDown(id);
          int mid=(l+r)>>1;
          int ans=inf;
          if(L<=mid)ans=min(ans,queryMin(lson(id),l,mid,L,R));
          if(R>mid)ans=min(ans,queryMin(rson(id),mid+1,r,L,R));
          return ans;
      }
      int queryRangeSum(int x,int y){
          int ans=0;
          while(top[x]!=top[y]){
              if(dep[top[x]]<dep[top[y]])swap(x,y);
              ans+=querySum(1,1,n,num[top[x]],num[x]);
              x=fa[top[x]];
          }
          if(dep[x]>dep[y])swap(x,y);
          if(x!=y)ans+=querySum(1,1,n,num[x]+1,num[y]);
          return ans;
      }
      int queryRangeMax(int x,int y){
          int ans=-inf;
          while(top[x]!=top[y]){
              if(dep[top[x]]<dep[top[y]])swap(x,y);
              ans=max(ans,queryMax(1,1,n,num[top[x]],num[x]));
              x=fa[top[x]];
          }
          if(dep[x]>dep[y])swap(x,y);
          if(x!=y)ans=max(ans,queryMax(1,1,n,num[x]+1,num[y]));
          return ans;
      }
      
      int queryRangeMin(int x,int y){
          int ans=inf;
          while(top[x]!=top[y]){
              if(dep[top[x]]<dep[top[y]])swap(x,y);
              ans=min(ans,queryMin(1,1,n,num[top[x]],num[x]));
              x=fa[top[x]];
          }
          if(dep[x]>dep[y])swap(x,y);
          if(x!=y)ans=min(ans,queryMin(1,1,n,num[x]+1,num[y]));
          return ans;
      }
      void updateRange(int x,int y){
          while(top[x]!=top[y]){
              if(dep[top[x]]<dep[top[y]])swap(x,y);
              update(1,1,n,num[top[x]],num[x]);
              x=fa[top[x]];
          }
          if(dep[x]>dep[y])swap(x,y);
          if(x!=y)update(1,1,n,num[x]+1,num[y]);
      }
      int U[maxn],V[maxn];
      int main(){
          scanf("%d",&n);
          for(int i=1;i<=n-1;i++){
              int u,v,w;
              scanf("%d%d%d",&u,&v,&w);
              u++,v++;
              U[i]=u,V[i]=v; 
              addedge(u,v,w);
              addedge(v,u,w);
          }
          dfs1(1,0);
          dfs2(1,1);
          build(1,1,n);
          for(int i=1;i<=n-1;i++)V[i]=(dep[U[i]]<dep[V[i]]?V[i]:U[i]);
          int m;
          scanf("%d",&m);
          while(m--){
              char op[50];
              int x,y;
              scanf("%s%d%d",op,&x,&y);
              if(op[0]=='C')modify(1,1,n,num[V[x]],y);
              else if(op[0]=='N')updateRange(x+1,y+1);
              else if(op[0]=='S')printf("%d\n",queryRangeSum(x+1,y+1));
              else if(op[1]=='A')printf("%d\n",queryRangeMax(x+1,y+1));
              else if(op[1]=='I')printf("%d\n",queryRangeMin(x+1,y+1));
          }
          return 0;
      }
      
  • 相关阅读:
    [Baltic2013]ballmachine BZOJ3133
    [Jxoi2012]奇怪的道路 BZOJ3195 状压DP
    [Baltic 2011]Lamp BZOJ2346
    可并堆
    [Jsoi2016]最佳团体 BZOJ4753 01分数规划+树形背包/dfs序
    点分治
    J2EE WEB应用架构分析
    {经典}springmvc+mybatis+restful+webservice Jeesz分布式架构
    深入Spring Boot:那些注入不了的 Spring 占位符 ( ${} 表达式 )
    G1 垃圾收集器之对象分配过程
  • 原文地址:https://www.cnblogs.com/pmt2018/p/11196819.html
Copyright © 2020-2023  润新知