2018.05.13 题解

气运之末
首先,贪心的想法,我们肯定尽可能取最大的区间(取满 k 个)
由于每次操作都只改变一位,所以,最多会生成一个新区间,而第一个区间会失效。
因此我们可以维护一个递减的单调队列,队尾即为当前的答案,如果发现队尾已经失效,那么把队尾往前推。

如果没想到也没关系,我们还有办法。
无疑便是调最大的区间,我们把每个区间都塞到堆里(大根堆),每次看看堆顶是否已经失效,如果失效就杀掉再找。

最多进行 q 次操作,所以我们造出长度为 n+q 的序列(假设q次都是移位),然后刷 ST表。每次O(1)求当前这 n-k 个区间的最大值。

命运敕令
这么多操作,一个套一个,我们很想知道每个操作到底进行了几次。
首先不容置疑的是最后一个操作只进行了一次。
如果最后一次是 1 操作,那么倒数第二次也进行了一次(以此类推)。
如果最后一次是 2 操作,那么 L 到 R 区间里的操作都进行了 2 次。

如果一次操作进行了 k 次,(1 操作不讲)如果它是 2 操作,那么 L 到 R 的操作多进行了 k 次……

若我们倒过来处理,那么每次的操作次数都是确定的。

每次进行区间操作怎么整?
对于一个序列0 0 0 0 0 0 0
我们要把第 2 个到第 5 增加 3,那么我们只需给第 2 个+3,第 6 个-3,再造前缀和就好了。
前缀和操作可以利用树状数组来进行,所以只需用两个树状数组来维护操作次数和区间权值就好了(如果不嫌麻烦可以用线段树来代替)。
虚妄之诺
本章试卷最有质量的一道小题。
我们肯定考虑每个点对根节点的贡献。
对于每条以根节点为首的数链上:
这里写图片描述
表格中的数字表示某节点的权值 ^ 了根节点的次数。(^ 就是 XOR)

我们发现这个东西很类似与组合数。
进一步总结发现,第 x 次深度为 d 的节点 ^ 了根的次数为 C x + d + 1 d
因为 ^ 的逆运算就是它本身,所以一个节点对根有贡献,当且仅当 C x + d 1 d m o d 2 = 1
根据Lucas定理,我们可以推导出只有 ( x + d 1 ) & d = d 的情况下才能符合(详解部分,懂的跳过。首先自己看完Lucas定理,我们知道可把这个东西分成若干项 C 0 0 C 0 1 C 1 0 C 1 1 相乘的形式,其中只有 C 0 1 的值为0,so 二进制下 d 的每一位都 ≤ x+d-1,正好相当于推导出的式子)。
接下来我们进一步推导,式子可以变成 ( x 1 ) & d = 0 。这样就好判断多了

由于 Q 也是相当的大,所以我们希望可以更快地回答。根据式子我们可得,所有 x 在二进制下大于 最大深度 的位都是没用的!所以我们可以刷一趟 DP,求得当 x 为某个值时的解。

推荐ZH学长的博客

代码
第一题

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gt() getchar()
using namespace std;
const int maxn=1e5+5,maxm=3e5+5;
int n,k,q,a[maxn],tot,s[maxm];
struct hp{
    int x,R;
}h[maxm];
void put(int x,int R)
{
    h[++tot]=(hp){x,R};
    for (int fa=tot;fa>1;fa>>=1)
      if (h[fa].x>h[fa>>1].x) swap(h[fa],h[fa>>1]);
      else break;
}
void del()
{
    h[1]=h[tot--];
    for (int fa=1,son;fa<<1<=tot;fa=son)
    {
        if ((fa<<1|1)>tot||h[fa<<1].x>h[fa<<1|1].x) son=fa<<1;else son=fa<<1|1;
        if (h[fa].x>h[son].x) break;else swap(h[fa],h[son]);
    }
}
int main()
{
    scanf("%d%d%d",&n,&k,&q);
    for (int i=n;i>=1;i--) scanf("%d",a+i);
    for (int i=1;i<=n;i++)
    {
        s[i]=s[i-1]+a[i];
        if (i>=k) put(s[i]-s[i-k],i-k+1);
    }
    for (int i=1,L=1,R=1,nxt=n+1;i<=q;i++)
    {
        char ch=gt();while (ch!='?'&&ch!='!') ch=gt();
        if (ch=='!')
        {
            s[nxt]=s[nxt-1]+a[L];
            put(s[nxt]-s[nxt-k],nxt-k+1);
            L=L%n+1;nxt++;R++;
        }else
        {
            while (h[1].R<R) del();
            printf("%d\n",h[1].x);
        }
    }
    return 0;
}

第一题+1

#include<cstdio>
#define CT getchar()
const int maxn=3e5+5;
int n,k,Q,a[maxn],s[maxn],til,hea;
struct js{
    int s,x;
}q[maxn];
void put(int s,int x)
{
    for (;til>=hea;til--) if (q[til].s>s) break;
    q[++til]=(js){s,x};
}
int get(int L)
{
    for (;til>=hea;hea++) if (q[hea].x>=L) break;
    return q[hea].s;
}
int main()
{
    scanf("%d%d%d",&n,&k,&Q);
    for (int i=n;i;i--) scanf("%d",a+i),s[i]=a[i];
    for (int i=1;i<=n;i++) s[i]+=s[i-1];
    for (int i=1;i+k-1<=n;i++) put(s[i+k-1]-s[i-1],i);
    for (int i=1,L=1,now=n,p=0;i<=Q;i++)
    {
        char ch=CT;while(ch!='!'&&ch!='?')ch=CT;
        if (ch=='!')
        {
            L++;now++;p=p%n+1;
            s[now]=s[now-1]+a[p];
            put(s[now]-s[now-k],now-k+1);
        }else printf("%d\n",get(L));
    }
    return 0;
}

第二题

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e5+5,tt=1e9+7;
int n,m,tot,c1[maxn],c2[maxn];
struct js{
    int p,L,R;
}f[maxn];
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
void add(int *c,int x,int dat,int len){while (x<=len) c[x]=(c[x]+dat)%tt,x+=x&-x;}
int get(int *c,int x){int sum=0;while (x>0) sum=(sum+c[x])%tt,x-=x&-x;return sum;}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++) f[i].p=read(),f[i].L=read(),f[i].R=read();
    for (int i=m,sum;i>=1;i--)
    {
        if (f[i].p==1)
        {
            sum=get(c1,i)+1;
            add(c2,f[i].L,sum,n);
            add(c2,f[i].R+1,-sum,n);
        }else
        {
            sum=get(c1,i)+1;
            add(c1,f[i].L,sum,m);
            add(c1,f[i].R+1,-sum,m);
        }
    }
    for (int i=1;i<=n;i++) printf("%d%c",(get(c2,i)+tt)%tt,i==n?'\n':' ');
    return 0;
}

第二题+1

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e5+5,tt=1e9+7;
int n,m,tot;
LL c[maxn];
struct js{
    int p,L,R;
}f[maxn<<1];
struct tre{
    int L,R,son[2],s,la;
}t[maxn<<2];
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
void add(int x,int dat){while (x<=n) c[x]=(c[x]+dat)%tt,x+=x&-x;}
int get(int x){int sum=0;while (x>0) sum=(sum+c[x])%tt,x-=x&-x;return sum;}
int build(int L,int R)
{
    int mid=L+R>>1,now=++tot;
    t[now].L=L;t[now].R=R;
    if (L==R) return now;
    t[now].son[0]=build(L,mid);
    t[now].son[1]=build(mid+1,R);
    return now;
}
int inc(int &x,int y){x=(x+y)%tt;}
void addtre(int x,int le,int ri,LL dat)
{
    if (le<=t[x].L&&t[x].R<=ri) {inc(t[x].la,dat);inc(t[x].s,dat*(t[x].R-t[x].L+1)%tt);return;}
    if (le>t[x].R||ri<t[x].L) return;
    int mid=t[x].L+t[x].R>>1;
    if (mid>=le) addtre(t[x].son[0],le,ri,dat),t[x].s=(t[x].s+t[t[x].son[0]].s)%tt;
    if (mid+1<=ri) addtre(t[x].son[1],le,ri,dat),t[x].s=(t[x].s+t[t[x].son[1]].s)%tt;
}
int gettre(int x,int le,int ri)
{
    if (le<=t[x].L&&t[x].R<=ri) return t[x].s;
    if (le>t[x].R||ri<t[x].L) return 0;
    int Ls=t[x].son[0],Rs=t[x].son[1];
    if (Ls) inc(t[Ls].la,t[x].la),inc(t[Ls].s,(LL)t[x].la*(t[Ls].R-t[Ls].L+1)%tt);
    if (Rs) inc(t[Rs].la,t[x].la),inc(t[Rs].s,(LL)t[x].la*(t[Rs].R-t[Rs].L+1)%tt);
    t[x].la=0;
    int mid=t[x].L+t[x].R>>1,sum=0;
    if (mid>=le) sum+=gettre(t[x].son[0],le,ri);
    if (mid+1<=ri) sum+=gettre(t[x].son[1],le,ri);
    return sum%tt;
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++) f[i].p=read(),f[i].L=read(),f[i].R=read();
    build(1,m);
    for (int i=m,sum;i>=1;i--)
    {
        if (f[i].p==1)
        {
            sum=gettre(1,i,i)+1;
            add(f[i].L,sum);add(f[i].R+1,-sum);
        }else
        {
            sum=gettre(1,i,i)+1;
            addtre(1,f[i].L,f[i].R,sum);
        }
    }
    for (int i=1;i<=n;i++) printf("%d%c",(get(i)+tt)%tt,i==n?'\n':' ');
    return 0;
}

第三题

#include<cstdio>
#define LL long long
#define Q(x) ((x<<3)+(x<<1))
using namespace std;
const int maxn=2e5+5;
int n,q,tot,longest,len,lnk[maxn],nxt[maxn<<1],son[maxn<<1],dep[maxn];
bool vis[maxn];
LL a[maxn],f[maxn<<2],sum;
LL read()
{
    LL ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=Q(ret)+ch-'0',ch=getchar();
    return ret*f;
}
void add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
void dfs(int x)
{
    vis[x]=1;if (dep[x]>longest) longest=dep[x];
    for (int i=lnk[x],y=son[i];i;i=nxt[i],y=son[i])
      if (vis[y]) continue;else dep[y]=dep[x]+1,dfs(y);
}
int main()
{
    n=read(),q=read();
    for (int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
    for (int i=0;i<n;i++) a[i]=read();
    dfs(0);sum=1;
    while (longest>=sum) sum<<=1,len++;
    for (int i=0;i<n;i++) f[(~dep[i])&(sum-1)]^=a[i];
    for (int i=0;i<=len;i++)
     for (int j=0;j<=sum;j++)
       if (j>>i&1) f[j^1<<i]^=f[j];
    LL x;
    while (q--) x=(read()&(sum-1))-1,printf("%lld\n",x<0?a[0]:f[x]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/80326630