bzoj3720 Gty的妹子树

  树分块,每个点如果其父亲的块还未满,则并入,否则自己新建一个块,询问时完整包含于一个子树的块二分,不完整包含的块直接暴力找。

  代码

  

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<vector>
  4 #define fi first
  5 #define sc second
  6 #define mp make_pair
  7 #define pb push_back
  8 #define lb(x) (x&-x)
  9 using namespace std;
 10 const int N = 1000010;
 11 const int inf=(1<<30)-1+(1<<30);
 12 typedef long long ll;
 13 typedef pair<int,int> P;
 14 int dp,pre[N],p[N],tt[N],w[N],f[N],id[N],B,tot,ans;
 15 int n,m,i,a,b,j;
 16 vector<P> vec[N];
 17 vector<int> edge[N];
 18 void link(int x,int y)
 19 {
 20     dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
 21 }
 22 void dfs(int x,int fa)
 23 {
 24     int i=p[x];
 25     f[x]=fa;
 26     while (i)
 27     {
 28         if (tt[i]!=fa)
 29         {
 30             if (vec[id[x]].size()<B) 
 31             {
 32                 id[tt[i]]=id[x];
 33                 vec[id[tt[i]]].pb(mp(w[tt[i]],tt[i]));
 34             }
 35             else
 36             {
 37                 id[tt[i]]=++tot;
 38                 vec[id[tt[i]]].pb(mp(w[tt[i]],tt[i]));
 39                 edge[id[x]].pb(id[tt[i]]);
 40             }
 41             dfs(tt[i],x);
 42         }
 43         i=pre[i];
 44     }
 45 }
 46 void sgao(int x,int v)
 47 {
 48     int m,l,r,i;
 49     l=0;r=vec[x].size()-1;
 50     while (l<=r)
 51     {
 52         m=(l+r)>>1;
 53         if (vec[x][m].fi<=v) l=m+1;else r=m-1;
 54     }
 55     ans+=vec[x].size()-l;
 56     for (i=0;i<edge[x].size();i++)
 57     sgao(edge[x][i],v);
 58 }
 59 void gao(int x,int fa,int v)
 60 {
 61     if (w[x]>v) ans++;
 62     int i=p[x];
 63     while (i)
 64     {
 65         if (tt[i]!=fa)
 66         {
 67             if (id[tt[i]]==id[x])
 68             gao(tt[i],x,v);
 69             else
 70             sgao(id[tt[i]],v);
 71         }
 72         i=pre[i];
 73     }
 74 }
 75 int main()
 76 {
 77     scanf("%d",&n);
 78     B=400;
 79     for (i=1;i<n;i++)
 80     {
 81         scanf("%d%d",&a,&b);
 82         link(a,b);link(b,a);
 83     }
 84     for (i=1;i<=n;i++)
 85     scanf("%d",&w[i]);
 86     vec[id[1]].pb(mp(w[1],1));
 87     dfs(1,0);
 88     for (i=0;i<=tot;i++)
 89     sort(vec[i].begin(),vec[i].end());
 90     scanf("%d",&m); 
 91     for (i=1;i<=m;i++)
 92     {
 93         int typ;
 94         scanf("%d%d%d",&typ,&a,&b);
 95         a^=ans;b^=ans;
 96         if (typ==0)
 97         {
 98             ans=0;
 99             gao(a,f[a],b);
100             printf("%d\n",ans);
101         }    
102         else
103         if (typ==1)
104         {
105             w[a]=b;
106             for (j=0;j<vec[id[a]].size();j++)
107             if (vec[id[a]][j].sc==a) vec[id[a]][j].fi=b;
108             sort(vec[id[a]].begin(),vec[id[a]].end());
109         }
110         else
111         {
112             n++;f[n]=a;w[n]=b;
113             link(a,n);
114             if (vec[id[a]].size()<B)
115                 id[n]=id[a];
116             else
117             {
118                 id[n]=++tot;
119                 edge[id[a]].pb(id[n]);
120             }
121             vec[id[n]].pb(mp(w[n],n));
122             sort(vec[id[n]].begin(),vec[id[n]].end());
123         }
124     }
125 }

 

转载于:https://www.cnblogs.com/fzmh/p/5460117.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值