省队集训Round2 DAY2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/clover_hxy/article/details/73729843

T1

这里写图片描述
这里写图片描述

题解

首先前缀和的变化一定是连续的。那么对于每个区间,我们找到他最大值和最小值所在的位置,如果k在最小最大值之间,那么一定可以从最小值最大值位置所构成的区间中得到。
那么根据单调性二分就可以了。每次二分出一个位置用杜教筛计算一下。
对于最大值最小值所在的位置可以打表啊。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 500003
#define LL long long 
using namespace std;
int prime[N],pd[N],n,L,R;
LL mu[N],k;
map<int,LL> mp;
void init(int n)
{
    mu[1]=1;
    for (int i=2;i<=n;i++) {
        if (!pd[i]) {
            prime[++prime[0]]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=prime[0];j++) {
            if (prime[j]*i>n) break;
            pd[prime[j]*i]=1;
            if (i%prime[j]==0) break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for (int i=2;i<=n;i++) mu[i]+=mu[i-1];
}
LL solve(int n)
{
    if (n<=500000) return mu[n];
    if (mp[n]) return mp[n];
    LL ans=1;
    for (int i=2,j;i<=n;i=j+1) {
        j=n/(n/i);
        ans-=solve(n/i)*(j-i+1);
    }
    mp[n]=ans;
    return ans;
}
int main()
{
    freopen("a.in","r",stdin);
    scanf("%d%lld",&n,&k); init(N-3);
    if(n==1e9)  L=456877618,R=903087703;
    if(n==1e7)  L=7109113,R=9995566;
    if(n==1e5)  L=48512,R=96017;
    LL l=solve(L); LL r=solve(R);
    if (l<=r) if (k<l||k>r) {
         printf("-1\n");
         return 0;
    }
    if (r<=l) if (k>l||k<r) {
        printf("-1\n");
        return 0;
    }
    while (L<=R) {
        int mid=(L+R)/2;
        LL t=solve(mid);
        if (t==k) {
            printf("%d\n",mid);
            return 0;
        } 
        if (l>r) {
          if (t<k) R=mid-1,r=solve(R);
          if (t>k) L=mid+1,l=solve(L);
        }
        else {
          if (t>k) R=mid-1,r=solve(R);
          if (t<k) L=mid+1,l=solve(L);
        }
    }
    printf("-1\n");
}



T3

这里写图片描述
这里写图片描述

题解

这道题以前做过一个静态的,就是树在开始的时候直接建好,后面直接查询。
这道题的关键是需要看出集合的构建实际上是一颗树结构,每次就是找到所以点的lca然后新加入的点就是lca的一个新的儿子。
对于查询,我们需要对于所有点按照dfs序排序,然后容斥计算答案。一个点的贡献 val 就是他到根路径上所有 Ci 的和。所以我们需要用平衡树动态的维护dfs序和每个点的 val

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 1200003
using namespace std;
int ch[N][3],fa[N],delta[N],val[N],a[N],ci[N],b[N],n;
int l[N],r[N],cnt,root,f[N][21],mi[21],deep[N],size[N];
int tot,point[N],nxt[N],v[N],sz;
struct data{
   int a,b;
}q[N];
void pushdown(int x)
{
   if (!delta[x]) return;
   int l=ch[x][0]; int r=ch[x][1];
   val[l]+=delta[x]; delta[l]+=delta[x];
   val[r]+=delta[x]; delta[r]+=delta[x];
   delta[x]=0;
}
int get(int x)
{
   return ch[fa[x]][1]==x;
}
void update(int x)
{
   size[x]=1;
   if (ch[x][1]) size[x]+=size[ch[x][1]];
   if (ch[x][0]) size[x]+=size[ch[x][0]];
}
void rotate(int x)
{
  int y=fa[x]; int z=fa[y];
  pushdown(y); pushdown(x);
  int which=get(x);
  ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
  ch[x][which^1]=y; fa[y]=x;
  if (z) ch[z][ch[z][1]==y]=x;
  fa[x]=z;
  update(y); update(x);
}
void splay(int x,int tar)
{
    for (int f1;(f1=fa[x])!=tar;rotate(x))
     if (fa[f1]!=tar)
      rotate(get(f1)==get(x)?f1:x);
    if (!tar) root=x;
}
int pre()
{
  int x=ch[root][0];
  while (ch[x][1]) x=ch[x][1];
  return x;
}
int next()
{
  int x=ch[root][1];
  while (ch[x][0]) x=ch[x][0];
  return x;
}
void build(int x,int y)
{
   tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
   deep[y]=deep[x]+1;
   f[y][0]=x;
   for (int i=1;i<=19;i++) {
    if (deep[y]-mi[i]<0) break;
    f[y][i]=f[f[y][i-1]][i-1];
   }
}
void add(int f1,int v,int x)
{
   l[x]=++cnt; r[x]=++cnt;
   splay(l[f1],0);
   val[l[x]]=val[root]+v;
   ci[l[x]]=v; size[l[x]]=1; size[r[x]]=1;
   splay(r[f1],0); int aa=pre();
   splay(aa,0); splay(r[f1],root);
   ch[ch[root][1]][0]=l[x];
   fa[l[x]]=ch[root][1];
   update(ch[root][1]); update(root);
   splay(r[f1],0); aa=pre();
   splay(aa,0); splay(r[f1],root);
   ch[ch[root][1]][0]=r[x];
   fa[r[x]]=ch[root][1]; 
   update(ch[root][1]); update(root);
}
int lca(int x,int y)
{
   if (deep[x]<deep[y]) swap(x,y);
   int k=deep[x]-deep[y];
   for (int i=0;i<=19;i++) 
    if ((k>>i)&1) x=f[x][i];
   if (x==y) return x;
   for (int i=19;i>=0;i--)
    if (f[x][i]!=f[y][i]) 
     x=f[x][i],y=f[y][i];
   return f[x][0];
}
int cmp(data a,data b)
{
   return a.b<b.b;
}
int main()
{
   freopen("san.in","r",stdin);
   freopen("san.out","w",stdout);
   scanf("%d",&n);
   root=1; mi[0]=1;
   for (int i=1;i<=20;i++) mi[i]=mi[i-1]*2;
   l[0]=1; r[0]=2;
   fa[2]=1; ch[1][1]=2;
   size[2]=1; size[1]=2; cnt=2;
   int ans=0;
   for (int i=1;i<=n;i++) {
    char s[10]; scanf("%s",s+1);
    if(s[1]=='A') {
       int k,x; scanf("%d",&k); ++sz;
       for (int j=1;j<=k;j++) scanf("%d",&a[j]),a[j]^=ans;
       scanf("%d",&x);
       if (k==0) {
        add(0,x,sz);
        build(0,sz);
        continue;
       }
       if (k==1) {
        add(a[1],x,sz); 
        build(a[1],sz);
        continue;
       }
       int t=lca(a[1],a[2]); 
       for (int j=3;j<=k;j++) t=lca(t,a[j]);
       add(t,x,sz);
       build(t,sz);
    }
    if (s[1]=='U') {
       int x,v; scanf("%d%d",&x,&v);
       splay(l[x],0); int aa=pre(); 
       int k=v-ci[root]; ci[root]=v;
       splay(r[x],0); int bb=next();
       splay(aa,0); splay(bb,aa);
       int t=ch[ch[root][1]][0];
       val[t]+=k; delta[t]+=k; 
    }
    if (s[1]=='Q') {
       int k; scanf("%d",&k);
       for (int j=1;j<=k;j++) scanf("%d",&q[j].a);
       for (int j=1;j<=k;j++) {
         splay(l[q[j].a],0);
         q[j].b=size[ch[root][0]]+1;
       }
       sort(q+1,q+k+1,cmp);
       ans=0;
       splay(l[q[1].a],0);
       ans+=val[root]; 
       for (int j=2;j<=k;j++) {
        int t=lca(q[j-1].a,q[j].a);
        splay(l[q[j].a],0);
        ans+=val[root]; 
        splay(l[t],0);
        ans-=val[root];
       }
      printf("%d\n",ans);
    }
   }
}

猜你喜欢

转载自blog.csdn.net/clover_hxy/article/details/73729843