• 2020暑假集训做题记录——数据结构


    题目质量很赞。这么多道数据结构,却不全是很裸的板子,并且带有卡常题

    A:模拟

    WA了好几发,贼蠢的题,非负整数是个坑

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 2000050
     5 using namespace std;
     6 
     7 int T,n;
     8 char str[N1];
     9 
    10 int main()
    11 {
    12     scanf("%d",&T);
    13     while(T--)
    14     {
    15         scanf("%d",&n);
    16         if(!n){ puts("0"); continue; }
    17         scanf("%s",str+1);
    18         int cnt=0,tot=0;
    19         for(int i=1;i<=n;i++)
    20         {
    21             if(str[i]=='('){
    22                 cnt++;
    23             }else{
    24                 if(cnt>0) cnt--, tot+=2;
    25             }
    26         }
    27         printf("%d
    ",n-tot);
    28     }
    29     return 0;
    30 }
    View Code

    B:图论

    a[i]向i连边,由于每个点入度都是1,发现图中每个连通块都是基环树,并且只能是环向外有出边。所以连通块个数就是答案

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 1000050
     5 #define M1 N1*2
     6 using namespace std;
     7 
     8 struct Edge{
     9 int to[M1],nxt[M1],head[N1],cte;
    10 void ae(int u,int v)
    11 {cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
    12 }e;
    13 int T,n;
    14 int a[N1],used[N1];
    15 void dfs(int u)
    16 {
    17     used[u]=1;
    18     for(int j=e.head[u];j;j=e.nxt[j])
    19     {
    20         int v=e.to[j]; if(used[v]) continue;
    21         dfs(v);
    22     }
    23 }
    24 
    25 int main()
    26 {
    27     scanf("%d",&n);
    28     int ans=0;
    29     for(int i=1;i<=n;i++) 
    30     {
    31         scanf("%d",&a[i]);
    32         if(i!=a[i]) e.ae(a[i],i), e.ae(i,a[i]);
    33     }
    34     for(int i=1;i<=n;i++) 
    35     {
    36         if(!used[i]) dfs(i), ans++;
    37     }
    38     printf("%d
    ",ans);
    39     return 0;
    40 }
    View Code

    C:树状数组

    设s[i]是前缀和。考虑暴力做法:枚举i,j(i>j>=0),统计满足s[i]-s[j]<=k(i-j)的i,j对数就行了。正解就挪一下式子,把i,j移到两侧,得到s[i]-ki<=s[j]-kj。所以预处理出所有s[i]-ki,离散一下用树状数组维护就行。不想离散就动态开点线段树2333。统计出来以后gcd一下就行。注意离散化的时候从第2位开始赋离散后的值

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 200010
     5 #define M1 N1*2
     6 #define ll long long 
     7 using namespace std;
     8 
     9 ll gcd(ll a,ll b)
    10 {
    11     if(!b) return a;
    12     return gcd(b,a%b);
    13 }
    14 int n,m; ll K;
    15 int a[N1],pos[N1];
    16 ll sa[N1];
    17 
    18 struct Bit{
    19 ll sum[N1];
    20 void upd(int x,int w){
    21     for(int i=x;i<=m;i+=i&(-i)) sum[i]+=w;
    22 }
    23 ll query(int x)
    24 {
    25     ll ans=0;
    26     for(int i=x;i>0;i-=i&(-i)) ans+=sum[i];
    27     return ans;
    28 }
    29 }s;
    30 struct node{
    31 int id; ll w;
    32 }sp[N1];
    33 int cmp(node a1,node a2)
    34 {
    35     if(a1.w!=a2.w) return a1.w<a2.w;
    36     return a1.id<a2.id; 
    37 }
    38 
    39 int main()
    40 {
    41     freopen("a.txt","r",stdin);
    42     scanf("%d%lld",&n,&K);
    43     for(int i=1;i<=n;i++) scanf("%d",&a[i]), sa[i]=sa[i-1]+a[i];
    44     for(int i=1;i<=n;i++) sp[i].w=sa[i]-K*i, sp[i].id=i;
    45     sp[n+1]=(node){0,0};
    46     sort(sp+1,sp+n+2,cmp); 
    47     m=1, pos[sp[1].id]=m;
    48     for(int i=2;i<=n+1;i++)
    49     {
    50         if(sp[i-1].w!=sp[i].w) m++;
    51         pos[sp[i].id]=m;
    52     }
    53     s.upd(pos[n],1); ll ans=0;
    54     for(int i=n-1;i>=0;i--)
    55     {
    56         ans+=s.query(pos[i]);
    57         s.upd(pos[i],1);
    58     }
    59     // printf("%lld
    ",ans);
    60     ll t1=ans,t2=1ll*(n+1)*n/2, g=gcd(t1,t2);
    61     printf("%lld/%lld
    ",t1/g,t2/g);
    62     return 0;
    63 }
    View Code

    D:线段树

    很普通的线段树题,我还卡了将近40min,菜爆了

    线段树维护一下?记录f[rt][0]表示左侧余下的)数量,f[rt][1]表示右侧余下(的数量,这两个变量用于判断括号序列是否合法,它们向上合并的式子并不难。再考虑最大嵌套怎么求,考虑暴力做法,打差分,把(当成+1,)当成-1,求一次前缀和,因为保证括号序列合法,求完以后序列元素的最大值就是最大嵌套层数。把这个做法扔线段树里就可以动态了!当前区间的答案就是max(左区间答案,左区间前缀和+右区间答案)。

    左侧多余的)和右侧多余的(不必特殊讨论,因为它们迟早得被匹配上,假设左右都给补全就行。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N1 1000005
     5 #define M1 N1*4
     6 #define ll long long 
     7 using namespace std;
     8 
     9 struct SEG{
    10 int f[M1][2],sum[M1],ma[M1];
    11 #define ls rt<<1
    12 #define rs rt<<1|1
    13 void pushup(int rt)
    14 {
    15     f[rt][0]=f[ls][0]+max(f[rs][0]-f[ls][1],0); //left remain ) -1
    16     f[rt][1]=f[rs][1]+max(f[ls][1]-f[rs][0],0); //right remain ( 1
    17     sum[rt]=sum[ls]+sum[rs];
    18     ma[rt]=max(ma[ls],sum[ls]+ma[rs]);
    19 }
    20 void upd(int x,int l,int r,int rt,int w)
    21 {
    22     if(l==r){
    23         if(w==-1) f[rt][0]=1, f[rt][1]=0;  // )
    24         if(w==0)  f[rt][0]=0, f[rt][1]=0;  // *
    25         if(w==1)  f[rt][0]=0, f[rt][1]=1;  // (
    26         sum[rt]=w, ma[rt]=w; return; 
    27     }
    28     int mid=(l+r)>>1;
    29     if(x<=mid) upd(x,l,mid,ls,w);
    30     else upd(x,mid+1,r,rs,w);
    31     pushup(rt);
    32 }
    33 #undef ls
    34 #undef rs
    35 }s;
    36 
    37 int check()
    38 {
    39     if(s.sum[1] || s.f[1][0] || s.f[1][1]) return -1;
    40     return s.ma[1];
    41 }
    42 
    43 int n,ma,mi,m;
    44 char comd[N1],str[N1];
    45 
    46 int main()
    47 {
    48     freopen("a.txt","r",stdin);
    49     scanf("%d",&n); 
    50     if(!n) return 0;
    51     scanf("%s",comd+1);
    52     int tmp=0,pos,ans;
    53     ma=0,mi=0;
    54     for(int i=1;i<=n;i++) 
    55         if(comd[i]=='R') tmp++, ma=max(ma,tmp);
    56         else if(comd[i]=='L') tmp--, mi=min(mi,tmp);
    57     pos=1-mi; m=ma-mi+1;
    58     for(int i=1;i<=n;i++)
    59     {
    60         if(comd[i]=='L') pos--;
    61         else if(comd[i]=='R') pos++;
    62         else if(comd[i]=='(') s.upd(pos,1,m,1,1);
    63         else if(comd[i]==')') s.upd(pos,1,m,1,-1);
    64         else s.upd(pos,1,m,1,0);
    65         ans=check();
    66         printf("%d ",ans);
    67     }
    68     puts("");
    69     return 0;
    70 }
    View Code

    E:二维RMQ维护gcd

    板子题,看到n=500以为$O(n^{3}+n^{2}log^{2}n)$能卡过,结果一直T,咋卡常也没用,数据很强。会寝室路上突然想到RMQ可以拓展到二维,枚举每个点再二分答案就行了,可以优化成$O(n^{2}logn+n^{2}log^{2}n)$。回去写了一发,终于过了

     1 #include <ctime>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define N1 505
     6 #define ll long long 
     7 using namespace std;
     8 
     9 inline int gcd(int x,int y)
    10 {
    11     if(!y) return x;
    12     return gcd(y,x%y);
    13 }
    14 template <typename _T> void read(_T &ret)
    15 {
    16     ret=0; _T fh=1; char c=getchar();
    17     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    18     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    19     ret=ret*fh;
    20 }
    21 
    22 int n,m,ma;
    23 int a[N1][N1],lg[N1];
    24 int g[N1][N1][12];
    25 int qg(int x,int y,int len)
    26 {
    27     return gcd( gcd( g[x][y][lg[len]],g[x][y+len-1-(1<<lg[len])+1][lg[len]]) , gcd(g[x+len-1-(1<<lg[len])+1][y][lg[len]], g[x+len-1-(1<<lg[len])+1][y+len-1-(1<<lg[len])+1][lg[len]]) ) ;
    28 }
    29 
    30 int main()
    31 {
    32     scanf("%d%d",&n,&m);
    33     clock_t st,ed;
    34     st=clock();
    35     for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
    36     ma=max(n,m); lg[1]=0;
    37     int ans=0,num=0;
    38     for(int i=2;i<=ma;i++) lg[i]=lg[i>>1]+1;
    39     for(int i=1;i<=n;i++) 
    40     {
    41         for(int j=1;j<=m;j++) g[i][j][0]=a[i][j];
    42     }
    43     for(int k=1;k<=lg[ma];k++)
    44     for(int i=1;i+(1<<k)-1<=n;i++) 
    45     {
    46         for(int j=1;j+(1<<k)-1<=m;j++) 
    47         {
    48             g[i][j][k]=gcd( gcd(g[i][j][k-1],g[i][j+(1<<(k-1))][k-1]) , gcd(g[i+(1<<(k-1))][j][k-1],g[i+(1<<(k-1))][j+(1<<(k-1))][k-1]) );
    49         }
    50     }
    51     int tmp,l,r,mid,k;
    52     for(int i=1;i<=n;i++)
    53     for(int j=1;j<=m;j++)
    54     {
    55         k=0, l=1, r=min(min(m-j,j-1),min(n-i,i-1));
    56         while(l<=r)
    57         {
    58             mid=(l+r)>>1; tmp=qg(i-mid,j-mid,2*mid+1);
    59             if(tmp%a[i][j]==0) k=mid, l=mid+1;
    60             else r=mid-1;
    61         }
    62         if((2*k+1)*(2*k+1)>ans) ans=(2*k+1)*(2*k+1), num=1;
    63         else if((2*k+1)*(2*k+1)==ans) num++;
    64     }
    65     printf("%d
    %d
    ",ans,num);
    66     return 0;
    67 }
    View Code

    F:贪心+set 好题

    考虑一条链的情况,搞个set记录现在有哪些佣兵可用,再用田忌赛马策略。对于每个任务,找后继(第一个比需要的能力值大的忍者),如果没有后继,就把最次的佣兵安排上。

    环怎么办。。。卡了1h多想不出弃疗看题解去了

    看了byaidu学长的题解,原来可以断环??!

    如果佣兵和任务是一一映射,那么答案唯一,特判一下就好

    对于其他的情况,会有的任务有很多佣兵,那么它之后的几个任务的佣兵都可以由它提供剩余的佣兵,它们之间可以互相影响。那么可能相互影响的任务一定是环上连续的一段。如果这一段的任务数量>1,那么最后一个肯定是空任务结尾,且它和前面的任务都不能影响后面的任务。整个序列都是一段的情况依然成立

    有了上面的结论,把环给转一下,就可以化成链,舍去尾对头的影响了!

    用链表实现任务的添加和删除,用set找后继

    另外vector是真不快

      1 #include <set>
      2 #include <ctime>
      3 #include <vector>
      4 #include <cstdio>
      5 #include <cstring>
      6 #include <algorithm>
      7 #define N1 500005
      8 #define ll long long 
      9 #define its set<int>::iterator
     10 #define itv vector<int>::iterator
     11 using namespace std;
     12 
     13 template <typename _T> void read(_T &ret)
     14 {
     15     ret=0; _T fh=1; char c=getchar();
     16     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     17     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     18     ret=ret*fh;
     19 }
     20 int n;
     21 int id[N1],a[N1],b[N1],num[N1];
     22 struct node{
     23     int l,r;
     24 }lst[N1];
     25 struct Edge{
     26 int to[N1],nxt[N1],head[N1],cte;
     27 void ae(int u,int v)
     28 { cte++; to[cte]=v, nxt[cte]=head[u], head[u]=cte; }
     29 }e;
     30 void pre_lst()
     31 {
     32     lst[1].l=n, lst[1].r=2;
     33     for(int i=2;i<n;i++) lst[i].l=i-1,lst[i].r=i+1;
     34     lst[n].l=n-1, lst[n].r=1;
     35 }
     36 int del(int i)
     37 {
     38     lst[lst[i].l].r=lst[i].r;
     39     lst[lst[i].r].l=lst[i].l;
     40     return lst[i].r;
     41 }
     42 int find_st()
     43 {
     44     pre_lst();
     45     int tot=n,i=1,res,st;
     46     while(tot)
     47     {
     48         if(!num[i]){ i=lst[i].r; continue; }
     49         res=num[i];
     50         while(res)
     51         {
     52             i=del(i); res--; tot--; 
     53             if(res==0) break;
     54             res+=num[i];
     55         }
     56     }
     57     if(!tot) st=(i==n?1:i+1); else st=i;
     58     return st;
     59 }
     60 set<int>s;
     61 vector<int>mer[N1];
     62 int solve(int i)
     63 {
     64     pre_lst();
     65     int tot=n,j,ans=0;its k;
     66     for(;tot;)
     67     {
     68         // if(!num[i]){ i=lst[i].r; continue; }
     69         for(j=0;j<mer[i].size();j++) s.insert(b[mer[i][j]]);
     70         // for(j=e.head[i];j;j=e.nxt[j]) s.insert(b[e.to[j]]);
     71         if(s.empty()){ i=lst[i].r; continue; }
     72         k=s.upper_bound(a[i]);
     73         if(k==s.end()){
     74             k=s.begin(); s.erase(*k);
     75         }else{
     76             s.erase(*k); ans++;
     77         }
     78         i=del(i), tot--; 
     79     }
     80     return ans;
     81 }
     82 
     83 int main()
     84 {
     85     // freopen("f.txt","r",stdin);
     86     // freopen("a.in","r",stdin);
     87     // freopen("f.out","w",stdout);
     88     clock_t sta,ed,tmp;
     89     sta=clock();
     90     scanf("%d",&n);
     91     for(int i=1;i<=n;i++) read(id[i]), num[id[i]]++;
     92     for(int i=1;i<=n;i++) mer[id[i]].emplace_back(i);
     93     // for(int i=1;i<=n;i++) read(id[i]), num[id[i]]++, e.ae(id[i],i);
     94     for(int i=1;i<=n;i++) read(a[i]); //任务
     95     for(int i=1;i<=n;i++) read(b[i]); //佣兵
     96     int flag=1; int ans=0;
     97     for(int i=1;i<=n;i++) if(num[i]!=1){ flag=0; break; }
     98     if(flag)
     99     {
    100         for(int i=1;i<=n;i++)
    101         {
    102             if(b[i]>a[id[i]]) ans++;
    103         }
    104         printf("%d
    ",ans); 
    105         return 0;
    106     }
    107     int st=find_st();
    108     ans=solve(st);
    109     printf("%d
    ",ans);
    110     // ed=clock(); printf("%.7lf s
    ",(double)(ed-sta)/CLOCKS_PER_SEC);
    111     return 0;
    112 }
    View Code

    G:线段树合并+离散化

    线段树合并板子题,但此题很毒瘤似乎卡空间,于是乎需要离散,把dis[x]和dis[x]+L一起离散2333

    线段树合并又又又又又又又又又又tnnd打错了,调了30minWA了2发,再打错我就是sb!

      1 #include <set>
      2 #include <ctime>
      3 #include <vector>
      4 #include <cstdio>
      5 #include <cstring>
      6 #include <algorithm>
      7 #define N1 400005
      8 #define ll long long 
      9 #define its set<int>::iterator
     10 #define itv vector<int>::iterator
     11 using namespace std;
     12 
     13 template <typename _T> void read(_T &ret)
     14 {
     15     ret=0; _T fh=1; char c=getchar();
     16     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     17     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     18     ret=ret*fh;
     19 }
     20 struct Edge{
     21 int to[N1],nxt[N1],head[N1],cte; ll val[N1];
     22 void ae(int u,int v,ll w)
     23 {
     24     cte++; to[cte]=v, nxt[cte]=head[u];
     25     head[u]=cte, val[cte]=w;
     26 }
     27 }e;
     28 struct SEG{; //2N*log*2
     29 int sum[N1*40],ls[N1*40],rs[N1*40],root[N1],cnt;
     30 void pushup(int rt){ sum[rt]=sum[ls[rt]]+sum[rs[rt]]; }
     31 void upd(int x,int l,int r,int &rt,int w)
     32 {
     33     if(!rt) rt=++cnt;
     34     // if(cnt>=N1*40) puts("-1");
     35     if(l==r){ sum[rt]+=w; return; }
     36     int mid=(l+r)>>1;
     37     if(x<=mid) upd(x,l,mid,ls[rt],w);
     38     else upd(x,mid+1,r,rs[rt],w);
     39     pushup(rt);
     40 }
     41 int mrg(int r1,int r2)
     42 {
     43     if(!r1||!r2) return r1+r2;
     44     int rt=++cnt;
     45     ls[rt]=mrg(ls[r1],ls[r2]);
     46     rs[rt]=mrg(rs[r1],rs[r2]);
     47     sum[rt]=sum[r1]+sum[r2];
     48     return rt;
     49 }
     50 int query(int L,int R,int l,int r,int rt)
     51 {
     52     if(L<=l&&r<=R) return sum[rt];
     53     int mid=(l+r)>>1,ans=0;
     54     if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
     55     if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]);
     56     return ans;
     57 }
     58 }s;
     59 int n,m; ll L;
     60 int dis[N1],disl[N1],ans[N1];
     61 struct node{ int id,p; ll w; }bar[N1];
     62 int cmp(node s1,node s2)
     63 { 
     64     if(s1.w!=s2.w) return s1.w<s2.w; 
     65     if(s1.p!=s2.p) return s1.p<s2.p; 
     66     return s1.id<s2.id; 
     67 }
     68 
     69 void dfs1(int u)
     70 {
     71     int j,v;
     72     bar[u].id=u; bar[u+n].id=u; bar[u].p=0; bar[u+n].p=1;
     73     bar[u+n].w=bar[u].w+L;
     74     for(j=e.head[u];j;j=e.nxt[j])
     75     {
     76         v=e.to[j]; 
     77         bar[v].w=bar[u].w+e.val[j]; 
     78         // dis[v]=dis[u]+e.val[j];
     79         dfs1(v);
     80     }
     81 }
     82 void dfs2(int u)
     83 {
     84     int j,v;
     85     s.upd(dis[u],1,m,s.root[u],1);
     86     for(j=e.head[u];j;j=e.nxt[j])
     87     {
     88         v=e.to[j]; 
     89         dfs2(v);
     90         s.root[u]=s.mrg(s.root[u],s.root[v]);
     91     }
     92     if(u==1)
     93         n=n;
     94     ans[u]=s.query(1,disl[u],1,m,s.root[u]);
     95 }
     96 int main()
     97 {
     98     read(n); read(L);
     99     int x; ll y;
    100     for(int i=2;i<=n;i++) read(x), read(y), e.ae(x,i,y);
    101     dfs1(1);
    102     sort(bar+1,bar+2*n+1,cmp); 
    103     bar[0].w=-1;
    104     for(int i=1;i<=2*n;i++) 
    105     {
    106         if(bar[i].w!=bar[i-1].w) m++;
    107         if(!bar[i].p) dis[bar[i].id]=m;
    108         else disl[bar[i].id]=m;
    109     }
    110     dfs2(1);
    111     for(int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    112     return 0;
    113 }
    View Code

    H:分块

    原来想了个拆询问+主席树的log方做法,写了一下发现是假的qwq。

    索性暴力分块。不过复习了分块也不错

    卡常卡半天我好难,实测块大小为250跑的最快。

     1 #include <ctime>
     2 #include <vector>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #define N1 100005
     7 #define M1 N1*4
     8 #define ll long long 
     9 using namespace std;
    10 
    11 template <typename _T> void read(_T &ret)
    12 {
    13     ret=0; _T fh=1; char c=getchar();
    14     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    15     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    16     ret=ret*fh;
    17 }
    18 const ll sq=250;
    19 
    20 int getid(int x){ return (x-1)/sq+1; }
    21 int n,K,m;
    22 int a[N1],tag[N1/sq+5],sum[N1/sq+5][N1];
    23 void pushdown(int id)
    24 {
    25     if(!tag[id]) return; 
    26     for(int i=(id-1)*sq+1;i<=id*sq;i++)
    27     {
    28         sum[id][a[i]]--;
    29         (a[i]+=tag[id])%=K;
    30         sum[id][a[i]]++;
    31     }
    32     tag[id]=0;
    33 }
    34 
    35 int main()
    36 {
    37     // freopen("h.txt","r",stdin);
    38     freopen("h.in","r",stdin);
    39     freopen("h0.out","w",stdout);
    40     clock_t sta,ed,tmp;
    41     sta=clock();
    42     read(n); read(K);
    43     for(int i=1;i<=n;i++) read(a[i]), a[i]=(a[i]%K+K)%K;
    44     read(m);
    45     int l,r,c,d,ans,lid,rid;
    46     for(int i=1;i<=n;i++)
    47     {
    48         sum[getid(i)][a[i]]++;
    49     }
    50     for(int k=1;k<=m;k++)
    51     {
    52         read(l); read(r); read(c); read(d); ans=0;
    53         c=(c%K+K)%K; d=(d%K+K)%K; 
    54         lid=getid(l); rid=getid(r); 
    55         pushdown(lid); pushdown(rid);
    56         if(lid==rid)
    57         {
    58             for(int i=l;i<=r;i++)
    59             {
    60                 if(a[i]==c) ans++;
    61                 sum[lid][a[i]]--; (a[i]+=d)%=K; sum[lid][a[i]]++;
    62             }
    63         }else{
    64             for(int i=l;i<=lid*sq;i++) 
    65             {
    66                 if(a[i]==c) ans++;
    67                 sum[lid][a[i]]--; (a[i]+=d)%=K; sum[lid][a[i]]++;
    68             }
    69             for(int i=lid+1;i<=rid-1;i++) 
    70             {
    71                 ans+=sum[i][(c-tag[i]+K)%K];
    72                 (tag[i]+=d)%=K;
    73             }
    74             for(int i=(rid-1)*sq+1;i<=r;i++) 
    75             {
    76                 if(a[i]==c) ans++;
    77                 sum[rid][a[i]]--; (a[i]+=d)%=K; sum[rid][a[i]]++;
    78             }
    79         }
    80         printf("%d
    ",ans);
    81     }
    82     // ed=clock(); printf("%.7lf s
    ",(double)(ed-sta)/CLOCKS_PER_SEC);
    83     return 0;
    84 }
    View Code

    I:种类并查集

    竟然不会了我太菜了,复习一波并查集拓展做法√

    种类并查集板子题,和NOI2001 食物链一个做法。开三倍的n记录点和点之间的关系

    并查集不能维护删边,所以我们倒着遍历询问变成了加边。注意删除同一个操作时需要在第一次(倒着看就是最后一次)删除的时候加边!

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 const int N1=100005;
     6 const int M1=1000005;
     7 
     8 template <typename _T> void read(_T &ret)
     9 {
    10     ret=0; _T fh=1; char c=getchar();
    11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    13     ret=ret*fh;
    14 }
    15 
    16 int n,K,m;
    17 int fa[N1*3];
    18 // vector<int>son[N1];
    19 int used[M1],prt[M1],cnt;
    20 struct comd{ int p,x,y; }des[M1],ques[M1];
    21 
    22 int findfa(int x)
    23 {
    24     int y=x,t;
    25     while(fa[y]!=y) y=fa[y];
    26     while(fa[x]!=y){ t=fa[x], fa[x]=y, x=t; }
    27     return y;
    28 }
    29 int mrg(int x,int y)
    30 {
    31     int fx=findfa(x), fy=findfa(y);
    32     if(fx==fy) return fx; 
    33     fa[fy]=fx;
    34     return fx;
    35 }
    36 int check(int x,int y)
    37 {
    38     if(findfa(x)==findfa(y)) return 1;
    39     return 0;
    40 }
    41 
    42 
    43 int main()
    44 {
    45     freopen("a.in","r",stdin);
    46     scanf("%d%d%d",&n,&K,&m);
    47     char str[10];
    48     for(int i=1;i<=K;i++) read(des[i].p), read(des[i].x), read(des[i].y);
    49     for(int i=1;i<=m;i++)
    50     {
    51         scanf("%s",str);
    52         if(str[0]=='q'){
    53             ques[i].p=1; read(ques[i].x); read(ques[i].y);
    54         }else{
    55             ques[i].p=2; read(ques[i].x); 
    56             if(!used[ques[i].x]) used[ques[i].x]=i;
    57         }
    58     }
    59     for(int i=1;i<=3*n;i++) fa[i]=i;
    60     int p,x,y,ans;
    61     for(int i=1;i<=K;i++)
    62     {
    63         if(used[i]) continue;
    64         p=des[i].p, x=des[i].x, y=des[i].y;
    65         if(p==1){
    66             mrg(x,y); mrg(x+n,y+n); mrg(x+2*n,y+2*n);
    67         }else{
    68             mrg(x+n,y); mrg(x+2*n,y+n); mrg(x,y+2*n);
    69         }
    70     }
    71     for(int j=m,i;j>=1;j--)
    72     {
    73         if(ques[j].p==1){
    74             x=ques[j].x, y=ques[j].y;
    75             if(check(x,y)&&check(x+n,y+n)&&check(x+2*n,y+2*n)) ans=0;
    76             else if(check(x+n,y)&&check(x+2*n,y+n)&&check(x,y+2*n)) ans=1;
    77             else if(check(y+n,x)&&check(y+2*n,x+n)&&check(y,x+2*n)) ans=2;
    78             else ans=3;
    79             prt[++cnt]=ans;
    80             // printf("%d
    ",ans);
    81         }else{       
    82             i=ques[j].x;
    83             if(used[i]!=j) continue; 
    84             p=des[i].p, x=des[i].x, y=des[i].y;
    85             if(p==1){
    86                 mrg(x,y); mrg(x+n,y+n); mrg(x+2*n,y+2*n);
    87             }else{
    88                 mrg(x+n,y); mrg(x+2*n,y+n); mrg(x,y+2*n);
    89             }
    90         }
    91     }
    92     for(int i=cnt;i>=1;i--) printf("%d
    ",prt[i]);
    93     return 0;
    94 }
    View Code

    J:点分治+01Trie

    把点分治给忘了我太弱了555,复习一波点分治板子√

    原来想了一个01Trie启发式合并,写了一下发现又是假做法。。

    统计链性质的问题多半都能用点分治搞呢

    对于每个点的点分树,暴力上01trie求解答案就行了= =

    怎么统计?按位分0/1讨论,r的答案减掉l-1的答案,注意l-1可能小于0

    转化成如下问题:

    已知数列$a$和数列$b$,要求有多少对$ai^bjle maxn$

    对$a$建成$01trie$,一次遍历$b$中每个元素求答案

    按位从高到低讨论,也就是在$01trie$上走

    如果$maxn$某一位是1:

    $bj$是0,$ai$这一位填0一定成立,答案加上$sum[ch(x,0)]$。填1不一定成立,需要看后面的位,走向1儿子

    $bj$是1,$ai$这一位填1一定成立,答案加上$sum[ch(x,1)]$。填0不一定成立,需要看后面的位,走向0儿子

    如果$maxn$某一位是0:

    $bj$是0,$ai$这一位只能填0而且需要看后面的位,走向0儿子

    $bj$是1,$ai$这一位只能填1而且需要看后面的位,走向1儿子

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define ll long long
      5 using namespace std;
      6 const int maxn=29;
      7 const int N1=100005;
      8 const int M1=3100005;
      9 template <typename _T> void read(_T &ret)
     10 {
     11     ret=0; _T fh=1; char c=getchar();
     12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     14     ret=ret*fh;
     15 }
     16 
     17 int n,l,r,de;
     18 struct Edge{
     19 int to[N1*2],nxt[N1*2],head[N1],cte;
     20 void ae(int u,int v)
     21 {cte++; to[cte]=v, nxt[cte]=head[u], head[u]=cte; }
     22 }e;
     23 struct Trie{
     24 int sum[M1],ch[M1][2],cnt;
     25 void clr()
     26 {
     27     for(int i=1;i<=cnt;i++) sum[i]=ch[i][0]=ch[i][1]=0;
     28     cnt=1;
     29 }
     30 void upd(int w)
     31 {
     32     int p,x=1;
     33     for(int i=maxn;i>=0;i--)
     34     {
     35         p=(w>>i)&1; 
     36         if(!ch[x][p]) ch[x][p]=++cnt; 
     37         x=ch[x][p]; sum[x]++;
     38     }
     39 }
     40 int query(int w,int m)
     41 {
     42     int ans=0,x=1;
     43     if(m<0) return 0;
     44     for(int i=maxn;i>=0;i--)
     45     {
     46         if((m>>i)&1){
     47             if((w>>i)&1) ans+=sum[ch[x][1]], x=ch[x][0]; // w 1  r 1
     48             else ans+=sum[ch[x][0]], x=ch[x][1]; // w 0  r 1
     49             if(!i) ans+=sum[x];
     50         }else{
     51             if((w>>i)&1) x=ch[x][1]; // w 1  r 0
     52             else x=ch[x][0]; // w 0  r 0
     53             if(!i) ans+=sum[x];
     54         }
     55     }
     56     return ans;
     57 }
     58 }t;
     59 
     60 int used[N1],sz[N1],ms[N1],tsz,G;
     61 void gra(int u,int dad)
     62 {
     63     sz[u]=1; ms[u]=0;
     64     for(int j=e.head[u];j;j=e.nxt[j])
     65     {
     66         int v=e.to[j];
     67         if(v==dad||used[v]) continue; 
     68         gra(v,u); sz[u]+=sz[v];
     69         ms[u]=max(ms[u],sz[v]);
     70     }
     71     ms[u]=max(ms[u],tsz-sz[u]);
     72     if(ms[u]<ms[G]) G=u;
     73 }
     74 int a[N1],sa0[N1],sa1[N1];
     75 void dfs0(int u,int dad)
     76 {
     77     for(int j=e.head[u];j;j=e.nxt[j])
     78     {
     79         int v=e.to[j]; if(v==dad||used[v]) continue; 
     80         sa0[v]=sa0[u]^a[v]; sa1[v]=sa1[u]^a[v];
     81         dfs0(v,u);
     82     }
     83 }
     84 ll dfs1(int u,int dad) //calc
     85 {
     86     ll ans=t.query(sa1[u],r);
     87     ans-=t.query(sa1[u],l-1);
     88     for(int j=e.head[u];j;j=e.nxt[j])
     89     {
     90         int v=e.to[j];
     91         if(v==dad||used[v]) continue; 
     92         ans+=dfs1(v,u);
     93     }
     94     return ans;
     95 }
     96 void dfs2(int u,int dad) //update in trie
     97 {
     98     t.upd(sa0[u]);
     99     for(int j=e.head[u];j;j=e.nxt[j])
    100     {
    101         int v=e.to[j];
    102         if(v==dad||used[v]) continue; 
    103         dfs2(v,u);
    104     }
    105 }
    106 ll calc(int u)
    107 {
    108     sa0[u]=a[u]; sa1[u]=0; dfs0(u,-1);
    109     t.upd(sa0[u]);
    110     ll ans=0;
    111     for(int j=e.head[u];j;j=e.nxt[j])
    112     {
    113         int v=e.to[j]; if(used[v]) continue; 
    114         ans+=dfs1(v,u); 
    115         dfs2(v,u);
    116     }
    117     t.clr();
    118     return ans;
    119 }
    120 ll main_dfs(int u)
    121 {
    122     ll ans=0;
    123     used[u]=1; ans+=calc(u);
    124     for(int j=e.head[u];j;j=e.nxt[j])
    125     {
    126         int v=e.to[j]; if(used[v]) continue; 
    127         G=0; tsz=sz[v]; gra(v,u);
    128         ans+=main_dfs(G);
    129     }
    130     return ans;
    131 }
    132 
    133 int main()
    134 {
    135     freopen("a.in","r",stdin);
    136     int x,y;
    137     scanf("%d%d%d",&n,&l,&r);
    138     for(int i=1;i<=n;i++) read(a[i]);
    139     for(int i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
    140     ms[0]=tsz=n; gra(1,-1); gra(G,-1);
    141     t.clr();
    142     ll ans=main_dfs(G);
    143     printf("%lld
    ",ans);
    144     return 0;
    145 }
    View Code

    K:贪心+单调栈

    把问题想象成把一个个元素放到后面填上去

    如果当前元素$a[i]$小于答案序列的最后一个元素$b[j]$,这个位置放$a[i]$会更优秀,但必须保证序列合法。

    那么如果$b[j]$可以被删除,仅当$i$小于$b[j]$在原序列中最后一次出现的位置

    如果$a[i]$大于等于$b[j]$就没有删除的必要了

    可能有多个$b[j]$被同时删除,用单调栈维护答案序列即可

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const int N1=1000005;
     7 
     8 template <typename _T> void read(_T &ret)
     9 {
    10     ret=0; _T fh=1; char c=getchar();
    11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    13     ret=ret*fh;
    14 }
    15 
    16 int n,K;
    17 int a[N1],la[N1],used[N1];
    18 int stk[N1],tp;
    19 
    20 int main()
    21 {
    22     freopen("a.in","r",stdin);
    23     scanf("%d%d",&n,&K);
    24     for(int i=1;i<=n;i++) read(a[i]), la[a[i]]=i;
    25     for(int i=1;i<=K;i++)
    26     {
    27         if(!la[i]){
    28             puts("Kanade"); return 0;
    29         }
    30     }
    31     for(int i=1;i<=n;i++)
    32     {
    33         if(used[a[i]]) continue;
    34         while(tp>0&&a[i]<stk[tp])
    35         {
    36             if(i<la[stk[tp]]) used[stk[tp]]=0, stk[tp]=0, tp--;
    37             else break;
    38         }
    39         stk[++tp]=a[i]; used[a[i]]=1;
    40     }
    41     for(int i=1;i<=tp;i++) printf("%d ",stk[i]);
    42     puts("");
    43     return 0;
    44 }
    View Code

    L:LCT维护树的连通性

    复习板子很开心

    既然是板子题,没啥可解释的

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const int N1=100005;
     7 
     8 template <typename _T> void read(_T &ret)
     9 {
    10     ret=0; _T fh=1; char c=getchar();
    11     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    12     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    13     ret=ret*fh;
    14 }
    15 
    16 struct LCT{
    17 int fa[N1],ch[N1][2],rev[N1];
    18 int idf(int x){ return ch[fa[x]][0]==x?0:1; }
    19 int isroot(int x){ return (ch[fa[x]][0]==x||ch[fa[x]][1]==x)?0:1; }
    20 void revers(int x){ swap(ch[x][0],ch[x][1]); rev[x]^=1; }
    21 void pushdown(int x){ if(rev[x]) revers(ch[x][0]), revers(ch[x][1]), rev[x]^=1; }
    22 void rot(int x)
    23 {
    24     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
    25     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
    26     fa[ch[x][px^1]]=y, ch[y][px]=ch[x][px^1];
    27     ch[x][px^1]=y; fa[y]=x;
    28     // pushup(y), pushup(x);
    29 }
    30 int stk[N1],tp;
    31 void splay(int x)
    32 {
    33     int y=x; stk[++tp]=x;
    34     while(!isroot(y)){ stk[++tp]=fa[y],y=fa[y]; }
    35     while(tp){ pushdown(stk[tp--]); }
    36     while(!isroot(x))
    37     {
    38         y=fa[x];
    39         if(isroot(y)) rot(x);
    40         else if(idf(y)==idf(x)) rot(y),rot(x);
    41         else rot(x),rot(x);
    42     }
    43 }
    44 void access(int x){ for(int y=0;x;y=x,x=fa[x]) splay(x),ch[x][1]=y; } // pushup(x);
    45 void mkroot(int x){ access(x),splay(x),revers(x); }
    46 void split(int x,int y){ mkroot(x),access(y),splay(y); }
    47 int fdroot(int x){ access(x),splay(x); while(ch[x][0]) pushdown(ch[x][0]),x=ch[x][0]; return x; }
    48 void cut(int x,int y){ split(x,y); fa[x]=ch[y][0]=0; } //pushup(y);
    49 void link(int x,int y){ split(x,y); fa[x]=y; } 
    50 int isconn(int x,int y){ mkroot(x); return fdroot(y)==x?1:0; } 
    51 }s;
    52 
    53 int n,m,de;
    54 
    55 int main()
    56 {
    57     freopen("a.in","r",stdin);
    58     read(n), read(m);
    59     int x,y,ans; char str[10];
    60     for(int i=1;i<=m;i++)
    61     {
    62         scanf("%s",str); read(x), read(y);
    63         if(str[0]=='+') s.link(x,y);
    64         if(str[0]=='-') s.cut(x,y);
    65         if(str[0]=='?') 
    66         {
    67             ans=s.isconn(x,y);
    68             if(ans) puts("Yes");
    69             else puts("No");
    70         }
    71     }
    72     return 0;
    73 }
    View Code

    M:待填坑(在学KD树)

    N:树链剖分

    又是一道板子题,把树剖复习了

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #define ll long long
      5 using namespace std;
      6 const int N1=100005;
      7 const int p=170001;
      8 
      9 template <typename _T> void read(_T &ret)
     10 {
     11     ret=0; _T fh=1; char c=getchar();
     12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     14     ret=ret*fh;
     15 }
     16 struct Edge{
     17 int to[N1*2],nxt[N1*2],head[N1],cte;
     18 void ae(int u,int v)
     19 { cte++; to[cte]=v, nxt[cte]=head[u], head[u]=cte; }
     20 }e;
     21 struct SEG{
     22 int sum[N1<<2],tag[N1<<2]; //****二倍
     23 void pushdown(int l,int r,int rt)
     24 {
     25     if(!tag[rt]) return;
     26     int mid=(l+r)>>1;
     27     (sum[rt<<1]+=1ll*tag[rt]*(mid-l+1)%p)%=p;
     28     (sum[rt<<1|1]+=1ll*tag[rt]*(r-mid)%p)%=p;
     29     (tag[rt<<1]+=tag[rt])%=p;  //***标记也要更新
     30     (tag[rt<<1|1]+=tag[rt])%=p;
     31     tag[rt]=0;
     32 }
     33 void pushup(int rt){ sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p; }
     34 void upd(int L,int R,int l,int r,int rt,int w)
     35 {
     36     if(L<=l&&r<=R)
     37     { 
     38         (sum[rt]+=1ll*w*(r-l+1)%p)%=p; 
     39         (tag[rt]+=w)%=p; 
     40         return; 
     41     }
     42     int mid=(l+r)>>1; pushdown(l,r,rt);
     43     if(L<=mid) upd(L,R,l,mid,rt<<1,w);
     44     if(R>mid) upd(L,R,mid+1,r,rt<<1|1,w);
     45     pushup(rt);
     46 }
     47 int query(int L,int R,int l,int r,int rt)
     48 {
     49     if(L<=l&&r<=R){ return sum[rt]; }
     50     int mid=(l+r)>>1,ans=0; pushdown(l,r,rt);
     51     if(L<=mid) (ans+=query(L,R,l,mid,rt<<1))%=p;
     52     if(R>mid) (ans+=query(L,R,mid+1,r,rt<<1|1))%=p;
     53     return ans;
     54 }
     55 }s;
     56 
     57 int n,m,de;
     58 int pos[N1],sz[N1],son[N1],fa[N1],dep[N1],tp[N1],tot;
     59 void dfs1(int u,int dad)
     60 {
     61     sz[u]=1;
     62     for(int j=e.head[u];j;j=e.nxt[j])
     63     {
     64         int v=e.to[j]; if(v==dad) continue;
     65         fa[v]=u, dep[v]=dep[u]+1;
     66         dfs1(v,u); sz[u]+=sz[v];
     67         son[u]=sz[v]>sz[son[u]]?v:son[u];
     68     }
     69 }
     70 void dfs2(int u)
     71 {
     72     pos[u]=++tot;
     73     if(son[u]) tp[son[u]]=tp[u], dfs2(son[u]);
     74     for(int j=e.head[u];j;j=e.nxt[j])
     75     {
     76         int v=e.to[j];
     77         if(v==fa[u]||v==son[u]) continue;
     78         tp[v]=v; dfs2(v);
     79     }
     80 }
     81 void update(int x,int y,int w)
     82 {
     83     while(tp[x]!=tp[y])
     84     {
     85         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
     86         s.upd(pos[tp[x]],pos[x],1,n,1,w);
     87         x=fa[tp[x]];
     88     }
     89     if(dep[x]>dep[y]) swap(x,y);
     90     s.upd(pos[x],pos[y],1,n,1,w);
     91 }
     92 int query(int x,int y)
     93 {
     94     int ans=0;
     95     while(tp[x]!=tp[y])
     96     {
     97         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
     98         (ans+=s.query(pos[tp[x]],pos[x],1,n,1))%=p;
     99         x=fa[tp[x]];
    100     }
    101     if(dep[x]>dep[y]) swap(x,y);
    102     (ans+=s.query(pos[x],pos[y],1,n,1))%=p;
    103     return ans;
    104 }
    105 int a[N1];
    106 
    107 int main()
    108 {
    109     freopen("a.in","r",stdin);
    110     read(n); read(m); int q,x,y,z,ans;
    111     for(int i=1;i<=n;i++) read(a[i]);
    112     for(int i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
    113     dep[1]=1; dfs1(1,-1);
    114     tp[1]=1; dfs2(1);
    115     for(int i=1;i<=n;i++) s.upd(pos[i],pos[i],1,n,1,a[i]);
    116     for(int i=1;i<=m;i++)
    117     {
    118         read(q);
    119         if(q==1){
    120             read(x), read(y), read(z);
    121             update(x,y,z);
    122         }else{
    123             read(x), read(y);
    124             ans=query(x,y);
    125             printf("%d
    ",ans);
    126         }
    127     }
    128     return 0;
    129 }
    130 
    131 // int lca(int x,int y)
    132 // {
    133 //     while(tp[x]!=tp[y])
    134 //     {
    135 //         if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
    136 //         x=fa[tp[x]];
    137 //     }
    138 //     return dep[x]<dep[y]?x:y;
    139 // }
    View Code

    O:线段树上二分

    又又是一道板子题

    线段树维护区间最大值

    询问怎么处理?询问的区间一定挂在$O(logn)$个线段树区间上,从左到右依次考虑每个线段树区间内是否存在某点符合要求,符合要求就在这个线段树区间内二分,总复杂度$O(mlogn)$

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const int N1=2000005;
     7 const int inf=0x3f3f3f3f;
     8 
     9 template <typename _T> void read(_T &ret)
    10 {
    11     ret=0; _T fh=1; char c=getchar();
    12     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
    13     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
    14     ret=ret*fh;
    15 }
    16 
    17 int n,m;
    18 int a[N1];
    19 
    20 struct SEG{
    21 int ma[N1<<2];
    22 void pushup(int rt){ ma[rt]=max(ma[rt<<1],ma[rt<<1|1]); }
    23 void upd(int x,int l,int r,int rt,int w)
    24 {
    25     if(l==r){ ma[rt]=w; return; }
    26     int mid=(l+r)>>1;
    27     if(x<=mid) upd(x,l,mid,rt<<1,w);
    28     else upd(x,mid+1,r,rt<<1|1,w);
    29     pushup(rt);
    30 }
    31 int found,ans;
    32 void find(int l,int r,int rt,int w)
    33 {
    34     if(l==r){ ans=l; return; }
    35     int mid=(l+r)>>1; 
    36     if(ma[rt<<1]>=w) find(l,mid,rt<<1,w);
    37     else find(mid+1,r,rt<<1|1,w);
    38 }
    39 void qlst(int L,int R,int l,int r,int rt,int w)
    40 {
    41     if(L<=l&&r<=R){ 
    42         if(ma[rt]>=w&&!found) find(l,r,rt,w), found=1;
    43         return ; 
    44     }
    45     int mid=(l+r)>>1; 
    46     if(L<=mid&&!found) qlst(L,R,l,mid,rt<<1,w);
    47     if(R>mid&&!found) qlst(L,R,mid+1,r,rt<<1|1,w);
    48 }
    49 int query(int L,int R,int w)
    50 {
    51     found=0, ans=-1;
    52     qlst(L,R,1,n,1,w);
    53     return ans;
    54 }
    55 }s;
    56 
    57 int main()
    58 {
    59     read(n); int x,y,ans;
    60     for(int i=1;i<=n;i++) read(a[i]), s.upd(i,1,n,1,a[i]);
    61     read(m); 
    62     for(int i=1;i<=m;i++)
    63     {
    64         read(x), read(y); x++, y=y-i+1;
    65         ans=s.query(x,n,y);
    66         if(ans==-1&&x>1) ans=s.query(1,x-1,y);
    67         if(ans==-1){ puts("-1"); continue; }
    68         if(ans>=x) printf("%d
    ",ans-x);
    69         else printf("%d
    ",n-(x-ans));
    70         s.upd(ans,1,n,1,-inf);
    71     }
    72     return 0;
    73 }
    View Code

    P:线段树+打表

    好题,赞

    一开始觉得线段树做不了写了个分块做法,卡了好久的常还是T。。看了眼题解,原来线段树可以做啊qwq

    首先推一下公式,我们有$x^{varphi (n)}=1(modspace p)$

    那么$x^{yspace modspacevarphi (p)}=1(modspace p)$,且$varphi (p)=p-1$

    现在只考虑指数$5^{k}space modspace (p-1)$,然后怎么办?似乎并没有什么可做的手段了啊

    打表发现$5^{k}space modspace (p-1)$的值竟然以27为循环节!

    那么问题转化成,现在有一个序列,每个位置有27种取值,取值构成一个环。每次修改让一段区间内的所有位置都取下一个值

    考虑用线段树维护,每个线段树区间根据其子区间的信息也可以得到27种取值

    还需要记录$pos$,表示当前线段树区间取的是第几个位置的值,再用标记$tag$维护$pos$数组

      1 #include <ctime>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #pragma GCC optimize(3)
      6 #define ll long long
      7 using namespace std;
      8 const int N1=200005;
      9 const int ma=27;
     10 const int p=73156157;
     11 const int phip=73156156;
     12 
     13 template <typename _T> void read(_T &ret)
     14 {
     15     ret=0; _T fh=1; char c=getchar();
     16     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
     17     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
     18     ret=ret*fh;
     19 }
     20 ll qpow(ll x,ll y)
     21 {
     22     ll ans=1;
     23     for(;y;x=x*x%p,y>>=1) if(y&1) ans=ans*x%p;
     24     return ans;
     25 }
     26 inline ll pow5(int x){ return 1ll*x*x%p*x%p*x%p*x%p; }
     27 
     28 int n,m,de;
     29 int a[N1];
     30 
     31 struct SEG{
     32 int sum[N1<<2][27],tag[N1<<2],pos[N1<<2];
     33 void pushdown(int rt)
     34 {
     35     if(!tag[rt]) return;
     36     (pos[rt<<1]+=tag[rt])%=ma, (pos[rt<<1|1]+=tag[rt])%=ma;
     37     (tag[rt<<1]+=tag[rt])%=ma, (tag[rt<<1|1]+=tag[rt])%=ma;
     38     pos[rt]=tag[rt]=0;
     39 }
     40 void pushup(int rt)
     41 {
     42     for(int j=0;j<ma;j++) 
     43         sum[rt][j]=(sum[rt<<1][(j+pos[rt<<1])%ma]+sum[rt<<1|1][(j+pos[rt<<1|1])%ma])%p;
     44 }
     45 void add(int L,int R,int l,int r,int rt)
     46 {
     47     if(L<=l&&r<=R){ (pos[rt]+=1)%=ma; (tag[rt]+=1)%=ma; return; }
     48     int mid=(l+r)>>1; pushdown(rt);
     49     if(L<=mid) add(L,R,l,mid,rt<<1);
     50     if(R>mid) add(L,R,mid+1,r,rt<<1|1);
     51     pushup(rt);
     52 }
     53 int query(int L,int R,int l,int r,int rt)
     54 {
     55     if(L<=l&&r<=R){ return sum[rt][pos[rt]]; }
     56     int mid=(l+r)>>1,ans=0; pushdown(rt);
     57     if(L<=mid) (ans+=query(L,R,l,mid,rt<<1))%=p;
     58     if(R>mid) (ans+=query(L,R,mid+1,r,rt<<1|1))%=p;
     59     pushup(rt);
     60     return ans;
     61 }
     62 void build(int l,int r,int rt)
     63 {
     64     if(l==r){
     65         sum[rt][0]=a[l];
     66         for(int j=1;j<ma;j++) sum[rt][j]=pow5(sum[rt][j-1]);
     67         return;
     68     }
     69     int mid=(l+r)>>1;
     70     build(l,mid,rt<<1);
     71     build(mid+1,r,rt<<1|1);
     72     pushup(rt);
     73 }
     74 }s;
     75 
     76 int main()
     77 {
     78     freopen("a.in","r",stdin);
     79     // freopen("a.out","w",stdout);
     80     // clock_t sta,ed;
     81     // sta=clock();
     82     read(n); read(m); 
     83     int fl,x,y; ll ans;
     84     for(int i=1;i<=n;i++) read(a[i]);
     85     s.build(1,n,1);
     86     for(int j=1;j<=m;j++)
     87     {
     88         read(fl), read(x), read(y);
     89         if(fl==1){
     90             s.add(x,y,1,n,1);
     91         }else{
     92             ans=0;
     93             ans=s.query(x,y,1,n,1);
     94             ans=ans*qpow(y-x+1,p-2)%p;
     95             printf("%lld
    ",ans);
     96         }
     97     }
     98     // ed=clock(); printf("%.7lf s
    ",(double)(ed-sta)/CLOCKS_PER_SEC);
     99     // printf("%.7lf s
    ",(double)(tot)/CLOCKS_PER_SEC);
    100     return 0;
    101 }
    View Code
  • 相关阅读:
    Ros与Vrep平台搭建
    场景采集难点
    写给师弟师妹论文排版秘籍
    采集项目笔记2
    采集项目记录1
    NLP&Python笔记——nltk模块基础操作
    Hash算法(含python实现)
    Python学习笔记——Socket通信
    Python学习笔记——GIF倒放处理
    OSError: [WinError 126] 找不到指定的模块 —— 解决办法
  • 原文地址:https://www.cnblogs.com/guapisolo/p/14128286.html
Copyright © 2020-2023  润新知