zoukankan      html  css  js  c++  java
  • UOJ #55 & 洛谷 P3920 紫荆花之恋 —— 动态点分治+替罪羊树

    题目:http://uoj.ac/problem/55

    https://www.luogu.org/problemnew/show/P3920

    参考博客:https://www.cnblogs.com/Khada-Jhin/p/10078584.html

    于是写了替罪羊树,但无论怎么调参都会T,UOJ上是80分。

    别忘记给 vis 赋值!!!

    更新答案和更新点分树一起做会错?总之分开写了;

    注意空间。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int Max(int x,int y){return x>y?x:y;}
    int const xn=1e5+5,inf=1e9,xm=40;
    int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],r[xn],fa[xn],dep[xn],f[xn][20];
    int tot,rt[xn],frt[xn],siz[xn*xm],ls[xn*xm],rs[xn*xm];//
    int size[xn],root,mx,sta[xn*xm],top;//sta
    int v[xn*xm],d[xn];//v
    ll ans;
    vector<int>pt[xn];
    bool vis[xn];
    void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
    int lca(int x,int y)
    {
      if(dep[x]<dep[y])swap(x,y);
      for(int i=19;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])x=f[x][i];
      for(int i=19;i>=0;i--)
        if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
      if(x==y)return x; return f[x][0];
    }
    int dist(int x,int y){return d[x]+d[y]-2*d[lca(x,y)];}
    int node(){if(top)return sta[top--]; return ++tot;}
    int *flag,tmp[xn*xm],tp;//flag
    void dfsx(int x)
    {
      if(!x)return;
      dfsx(ls[x]); tmp[++tp]=x; dfsx(rs[x]);
    }
    void solve(int &x,int l,int r)
    {
      if(l>r){x=0; return;}
      int mid=((l+r)>>1); x=tmp[mid];
      if(l==r){ls[x]=rs[x]=0; siz[x]=1; return;}
      solve(ls[x],l,mid-1); solve(rs[x],mid+1,r);
      siz[x]=siz[ls[x]]+siz[rs[x]]+1;
    }
    void rebuild(int &x)
    {
      tp=0; dfsx(x);
      solve(x,1,tp);
    }
    void ins(int &x,int val)
    {
      if(!x){x=node(); v[x]=val; siz[x]=1; return;}
      siz[x]++;
      if(val<=v[x])ins(ls[x],val);
      else ins(rs[x],val);
      if(siz[x]*86<=Max(siz[ls[x]],siz[rs[x]])*100)flag=&x;//
    }
    void insert(int &x,int val)
    {
      flag=0; ins(x,val);
      if(flag)rebuild(*flag);//
    }
    void del(int &x)
    {
      if(!x)return;
      del(ls[x]); del(rs[x]);
      siz[x]=v[x]=0; sta[++top]=x; x=0;
    }
    void getrt(int x,int ff,int sum)
    {
      int nmx=0; size[x]=1;
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if(vis[u=to[i]]||u==ff)continue;
          getrt(u,x,sum); size[x]+=size[u];
          nmx=Max(nmx,size[u]);
        }
      nmx=Max(nmx,sum-size[x]);
      if(mx>nmx)mx=nmx,root=x;
    }
    void dfs(int x,int ff)
    {
      size[x]=1; pt[root].pb(x);
      insert(rt[root],r[x]-dist(x,root));
      if(fa[root])insert(frt[root],r[x]-dist(x,fa[root]));
      for(int i=hd[x],u;i;i=nxt[i])
        if(!vis[u=to[i]]&&u!=ff)dfs(u,x),size[x]+=size[u];
    }
    void build(int x,int ff,int sum)
    {
      vis[x]=1;
      del(rt[x]); del(frt[x]);
      fa[x]=ff; pt[x].clear();//
      dfs(x,0);
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if(vis[u=to[i]])continue;
          //int ns=(size[u]>size[x]?sum-size[x]:size[u]);
          int ns=size[u];
          mx=inf; getrt(u,0,ns); build(root,x,ns);
        }
    }
    int find(int x,int val)
    {
      if(!x)return 0;
      if(val<=v[x])return siz[x]-siz[ls[x]]+find(ls[x],val);
      else return find(rs[x],val);
    }
    /*
    void work(int x)
    {
      int fl=0;
      rt[x]=node(); v[rt[x]]=r[x]; vis[x]=1;//
      for(int y=x;y;y=fa[y])
        {
          size[y]++; pt[y].pb(x);
          ll ds=dist(x,y),ds2;
          ans+=find(rt[y],ds-r[x]);
          if(fa[y])ans-=find(frt[y],(ds2=dist(x,fa[y]))-r[x]);
          if(fa[y]==y)exit(0);//--------
          insert(rt[y],r[x]-ds);
          if(fa[y])insert(frt[y],r[x]-ds2);
          if(fa[y]&&size[y]*10>(size[fa[y]]+1)*9)fl=fa[y];
        }
      if(fl)
        {
          for(int i=0;i<pt[fl].size();i++)vis[pt[fl][i]]=0;
          mx=inf; getrt(fl,0,size[fl]); build(root,fa[fl],size[fl]);
        }
    }
    */
    ll query(int x)
    {
      ll ret=0;
      for(int y=x;y;y=fa[y])ret+=find(rt[y],dist(x,y)-r[x]);
      for(int y=x;fa[y];y=fa[y])ret-=find(frt[y],dist(x,fa[y])-r[x]);
      return ret;
    }
    void work(int x)
    {
      int fl=-1;
      for(int y=x;y;y=fa[y])
        {
          size[y]++; pt[y].pb(x);
          insert(rt[y],r[x]-dist(x,y));
          if(fa[y])insert(frt[y],r[x]-dist(x,fa[y]));
          if(fa[y]&&size[y]*10>(size[fa[y]]+1)*8)fl=fa[y];//0
        }
      if(fl!=-1)
        {
          for(int i=0;i<pt[fl].size();i++)vis[pt[fl][i]]=0;
          int sum=size[fl];//
          mx=inf; getrt(fl,0,sum); build(root,fa[fl],sum);
        }
    }
    void init(int x,int ff,int w)
    {
      f[x][0]=ff; d[x]=d[ff]+w; dep[x]=dep[ff]+1; vis[x]=1;//vis!!!
      for(int i=1;i<20&&f[f[x][i-1]][i-1];i++)f[x][i]=f[f[x][i-1]][i-1];
    }
    int gt[35],gtp;
    void wr(ll x)
    {
      if(!x){puts("0"); return;}
      if(x<0)putchar('-'),x=-x; gtp=0;
      while(x)gt[++gtp]=x%10,x/=10;
      for(int i=gtp;i;i--)putchar(gt[i]+'0');
      puts("");
    }
    int main()
    {
      int T=rd(); n=rd(); ll lst=0;
      rd(); rd(); r[1]=rd(); vis[1]=1; size[1]=1; dep[1]=1;//
      insert(rt[1],r[1]); pt[1].pb(1); puts("0");
      for(int i=2,x,w;i<=n;i++)
        {
          x=(rd()^(lst%inf)); w=rd(); r[i]=rd();
          add(x,i); add(i,x);
          init(i,x,w); fa[i]=x; //work(i);
          ans+=query(i);
          //printf("%lld
    ",lst=ans);
          wr(lst=ans);
          work(i);
        }
      return 0;
    }
  • 相关阅读:
    SQLSERVER2008数据库增量备份还原方式
    使用VS2003遇到“无法显示进程。没有正确安装调试器。请运行安装程序安装或修复调试器。”的解决方法
    IIS7下配置最大上传附件大小需要注意的事项
    运行常用指令
    跨库查询推荐使用的方法
    获取客户端IP需要注意的一个问题
    如何判断一个表是否建立索引约束等信息的SQL语句
    SQLServer2005重建索引前后对比
    一个鼠标滚轮控制大小的缩放类。
    全兼容的纯CSS级联菜单
  • 原文地址:https://www.cnblogs.com/Zinn/p/10269395.html
Copyright © 2011-2022 走看看