• LOJ6276 果树


    (咕咕咕咕咕)

    (先挖坑)

    填坑

    题意:有一颗树,树上每个点有一个颜色,定义合法的路径为一条路径上所有点颜色都不相同,求有多少合法路径

    观察题面,题中有一个条件为每种颜色的点不超过20个,于是想到一种特殊的做法,枚举每种颜色中的点对,对于一个点对u,v,如果u是v的祖宗,则一个在v的子树里的点和一个不在与v所在相同的u的子树里的点是不合法的路径,如果u,v不是祖孙关系,则一个在u的子树与一个在v的子树里的点的路径是不合法的。我们将这些不合法的点对的起点与终点看作二维平面的x和y,将不合法的点对看作一个个矩形,因为这些点对都是在子树中的,所以先处理下dfs序就可以了,然后跑一个扫描线,剪掉不合法的就ok了(我扫描线不会写真是菜死了),在扫描线的时候应该要注意,起点和终点反过来计算重复的问题,我采用的方法是只考虑dfs序中起点大于终点的情况。

    代码如下

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    struct tree
    {
      int l,r,sum,lz,LZ;
    }t[N*4];
    struct edge
    {
      int to,next;
    }e[N*2];
    struct name
    {
      int l,r,q;
      name(){}
      name(int a,int b,int c)
      {
        l=a,r=b,q=c;
      }
      friend inline bool operator <(const name &a,const name &b)
      {
        return a.q>b.q;
      }
    };
    int head[N],ecnt;
    int n,c[N];
    ll ans;
    vector<int>vt[N];
    vector<name>v[N];
    void add(int u,int v)
    {
      e[++ecnt].to=v;e[ecnt].next=head[u];head[u]=ecnt;
    }
    int ti,dfn[N],pos[N],ed[N];
    void dfs(int u)
    {
      dfn[u]=++ti;pos[ti]=u;
      for(int i=head[u];i;i=e[i].next) if(!dfn[e[i].to]) dfs(e[i].to);
      ed[u]=ti;
    }
    void build(int p,int l,int r)
    {
      t[p].l=l;t[p].r=r;t[p].sum=0;t[p].lz=t[p].LZ=0;
      if(l==r) return (void)(t[p].sum=1);
      int mid=l+r>>1;
      build(p<<1,l,mid);
      build(p<<1|1,mid+1,r);
      t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
    }
    //只考虑dfs序起点大于终点的情况
    void adds(int xs,int xe,int ys,int ye)
    {
      if(xs>xe||ys>ye) return ; 
      if(xs>ys) swap(xs,ys),swap(xe,ye);
      v[xs].push_back(name(ys,ye,-1));
        v[xe+1].push_back(name(ys,ye,1));
        //printf("%d-%d//%d-%d
    ",xs,xe,ys,ye);
    }
    void work(int u,int v)
    {
      if(dfn[u]>dfn[v]) swap(u,v);
      if(dfn[v]>dfn[u] && dfn[v]<=ed[u])
        {
          for(int i=head[u],x;i;i=e[i].next)
        {
          x=e[i].to;
          if(dfn[v]>=dfn[x] && dfn[v]<=ed[x])
            {
            adds(1,dfn[x]-1,dfn[v],ed[v]);
            adds(ed[x]+1,n,dfn[v],ed[v]);
            }
        }
          
        }
      else
        {
          adds(dfn[u],ed[u],dfn[v],ed[v]);
        }
    }
    void push_down(int p)
    {
      if(t[p].l==t[p].r) return ;
      if(t[p].lz==0) return ;
      t[p<<1].lz+=t[p].lz;
      t[p<<1].LZ+=t[p].lz;
      if(t[p<<1].LZ<0) t[p<<1].sum=0;
      else t[p<<1].sum=t[p<<1].r-t[p<<1].l+1;
      t[p<<1|1].lz+=t[p].lz;
      t[p<<1|1].LZ+=t[p].lz;
      if(t[p<<1|1].LZ<0) t[p<<1|1].sum=0;
      else t[p<<1|1].sum=t[p<<1|1].r-t[p<<1|1].l+1;
      t[p].lz=0;
    }
    void modify(int p,int l,int r,int w)
    {
      if(t[p].l==l &&t[p].r==r)
        {
          t[p].lz+=w;
          if(t[p].lz<0) t[p].sum=0;
          else if(l==r) t[p].sum=1;
          else t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
          return ;
        }
      //  push_down(p);
      int mid=t[p].l+t[p].r>>1;
      if(mid>=r) modify(p<<1,l,r,w);
      else if(l>mid) modify(p<<1|1,l,r,w);
      else modify(p<<1,l,mid,w),modify(p<<1|1,mid+1,r,w);
      if(t[p].lz==0)t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
    }
    int query(int p,int l,int r)
    {
      if(t[p].l==l &&t[p].r==r) return /*printf("(%d,%d,%d)",l,r,t[p].sum),*/t[p].sum;
      int mid=t[p].l+t[p].r>>1;
      if(mid>=r) return query(p<<1,l,r);
      if(l>mid) return query(p<<1|1,l,r);
      return query(p<<1,l,mid)+query(p<<1|1,mid+1,r);
    }
    int main()
    {
      scanf("%d",&n);
      for(int i=1;i<=n;i++) scanf("%d",&c[i]),vt[c[i]].push_back(i);
      for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
      dfs(1);
      //  for(int i=1;i<=n;i++) printf("%d(%d)
    ",i,dfn[i]);
      for(int i=1,sz;i<=n;i++)
        {
          sz=vt[i].size();
          for(int j=0;j<sz;j++)
        for(int k=j+1;k<sz;k++)
          work(vt[i][j],vt[i][k]);
        }
      build(1,1,n);
      for(int i=1,sz;i<=n;i++)
        {
          sz=v[i].size();
          sort(v[i].begin(),v[i].end());
          for(int j=0;j<sz;j++)
        {
          name u=v[i][j];
          modify(1,u.l,u.r,u.q);
          //      printf("%d:%d-%d(%d)
    ",i,u.l,u.r,u.q);
        }
          int FAQ=query(1,i,n);
          //   printf("QUERY%d=%d
    ",i,FAQ);
          ans+=FAQ;
        }
      printf("%lld
    ",ans);
      return 0;
    }
    // 3 1 2 3 1 2 1 3
    // 5 1 1 2 3 3 1 2 1 3 2 4 2 5
  • 相关阅读:
    final和finally的区别
    ArrayList和LinkedList的区别
    collection和collections的区别
    第三次作业
    第二次作业
    第零次作业
    最后一次作业-- 总结报告
    第14、15教学周作业
    GridView去掉边框! 【转载于:http://magicpeng99.blog.sohu.com/】
    ASP.NET支持用Menu显示web.sitemap中定义好的网站链接 【转载】
  • 原文地址:https://www.cnblogs.com/pigba/p/8870828.html
Copyright © 2020-2023  润新知