• CSP-S模拟题(补几天的坑,62~69)


    模拟62

       Graph

        很显然的一个性质是旅行次数为一个联通块中边数/2向下取整,树DP+贪心走一边DFS即可求出方案

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> P;
    typedef pair<P,int> D;
    struct edge{
        int u,v;
        inline int get(int x){return x==u?v:u;}
    }e[200050];
    int N,M,last=0;
    bool vis[100050],used[200050];
    vector<int>to[100050];
    vector<D>ans;
    void dfs(int u,int pre){
        vis[u]=1;
        for(int i=0,y,v;i<to[u].size();++i){
            y=to[u][i];v=e[y].get(u);
            if(vis[v])continue;dfs(v,y);
        }
        for(int i=0,y,v;i<to[u].size();++i){
            y=to[u][i];v=e[y].get(u);
            if(used[y]||y==last||y==pre)continue;
            if(last)ans.push_back(D(P(e[last].get(u),v),u)),used[last]=1,used[y]=1,last=0;else last=y;
        }
        if(last&&pre){
            ans.push_back(D(P(e[last].get(u),e[pre].get(u)),u)),used[last]=1,used[pre]=1,last=0;
        }
    }
    
    int main(){
        cin>>N>>M;
        for(int i=1,u,v;i<=M;++i)scanf("%d%d",&u,&v),to[u].push_back(i),to[v].push_back(i),e[i].u=u,e[i].v=v;
        for(int i=1;i<=N;++i){
            last=0;
            if(!vis[i])dfs(i,0);
        }
        cout<<ans.size()<<endl;
        for(int i=0;i<ans.size();++i)cout<<ans[i].first.first<<" "<<ans[i].second<<" "<<ans[i].first.second<<endl;
    }
    /*
    4 5
    1 2
    3 2
    2 4
    3 4
    4 1
    
    */
    View Code

      Permutation 好题

        正串最小,反串最大(不会证明),解法是建边跑拓扑排序

    #include<iostream>
    #include<cstdio>
    #include<queue>
    using namespace std;
    int n,k,p[510000],q[510000],to[1010000],nex[1010000],head[510000],indu[510000],tot;
    int minn[2010000];
    struct node{
        int x;
        bool operator < (const node b)const{
            return x>b.x;
        }
    };
    priority_queue<node>qwq;
    void add(int x,int y){
        to[++tot]=y,nex[tot]=head[x],head[x]=tot;
        indu[y]++;
    }
    void add_point(int t,int l,int r,int x,int k){
        if(l==r){
            minn[t]=k;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x) add_point(t*2,l,mid,x,k);
        else add_point(t*2+1,mid+1,r,x,k);
        minn[t]=min(minn[t*2],minn[t*2+1]);
    }
    int query(int t,int l,int r,int L,int R){
        if(L>R) return n+1;
        if(L<=l&&r<=R){
            return minn[t];
        }
        int mid=(l+r)>>1,ans=n+1;
        if(mid>=L) ans=min(ans,query(t*2,l,mid,L,R));
        if(mid<R) ans=min(ans,query(t*2+1,mid+1,r,L,R));
        return ans;
    }
    void build(int t,int l,int r){
        minn[t]=n+1;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(t*2,l,mid);
        build(t*2+1,mid+1,r);
    }
    int main(){
        scanf("%d%d",&n,&k);
        for(register int i=1;i<=n;i++) scanf("%d",&p[i]),q[p[i]]=i;
        build(1,1,n);
        for(register int i=n;i>=1;i--){
            int x=query(1,1,n,max(1,q[i]-k+1),q[i]),y=query(1,1,n,q[i],min(n,q[i]+k-1));
            if(x<=n) add(q[i],q[x]);
            if(y<=n) add(q[i],q[y]);
            add_point(1,1,n,q[i],i);
        }
        for(register int i=1;i<=n;i++) if(indu[i]==0) qwq.push((node){i});
        int tm=0;
        while(qwq.size()){
            int x=qwq.top().x;qwq.pop();
            q[++tm]=x;
            for(register int i=head[x];i;i=nex[i]){
                int y=to[i];
                indu[y]--;
                if(indu[y]==0) qwq.push((node){y});
            }
        }
        for(register int i=1;i<=n;i++) p[q[i]]=i;
        for(register int i=1;i<=n;i++) printf("%d
    ",p[i]);
        
        
    }
    View Code

      Tree

        考虑让经过最小边的路径最少使得答案最大,那么可以发现是能够只走一次最小边,向下划分子问题,最后答案就是~边权和(-_- !)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n;
    long long ans;
    int main(){
        //freopen("3.in","r",stdin);
        //freopen("3.out","w",stdout);
        scanf("%d",&n);
        for(register int i=1,x,y,z;i<n;i++){
            scanf("%d%d%d",&x,&y,&z);
            ans+=z;
        }
        printf("%lld
    ",ans);
    }
    View Code

    模拟 63

      Median 好题

        离散化,数据可以看成是随机的,然后开桶记录数出现的次数,移动窗口的同时移动中位数,只是千万别sort(我不知道,我没改完,我被停  训了~因为没值日)

    #include<bits/stdc++.h>
    using namespace std;
    int n,k,w;
    long long tmp[11000000],S[11000000],prm[11000000],l,r,num1,num2;
    char vis[110000000];
    void move_right(){num1++,num2--,l++;while(tmp[l]==0&&l<=n) l++;}
    void move_left(){num1--,num2++,l--;while(tmp[l]==0&&l) l--;}
    struct node{
        int x,id,dis;
    }p[11000000];
    char cmp1(node a,node b){
        return a.x<b.x;
    }
    char cmp2(node a,node b){
        return a.id<b.id;
    }
    int main(){
        //freopen("1.in","r",stdin);
        //freopen("2.out","w",stdout);
        scanf("%d%d%d",&n,&k,&w);
        for(register int i=2;i<=100000000;i++){
            if(!vis[i]) prm[++prm[0]]=i;
            for(register int j=1;j<=prm[0]&&i*prm[j]<=100000000;j++){
                vis[i*prm[j]]=1;
                if(i%prm[j]==0) break;
            }
            if(prm[0]==n) break;
        }
        for(register int i=1;i<=n;i++){
            S[i]=prm[i]*i%w;
            p[i].x=S[i]+S[(int)floor(1.0*i/10.0)+1];
            p[i].id=i;
        }
        sort(p+1,p+n+1,cmp1);
        for(register int i=1;i<=n;i++){
            p[i].dis=i,S[i]=p[i].x;
        }
        sort(p+1,p+n+1,cmp2);
        double ans=0;
        if(k&1){
            l=p[1].dis;
            tmp[p[1].dis]++;
            for(register int i=2;i<=k;i++){
                tmp[p[i].dis]++; 
                if(p[i].dis>l) num2++;
                else num1++;
            }
            while(num1<num2) move_right();
            while(num2<num1) move_left();
            ans+=S[l];
            for(register int i=k+1;i<=n;i++){
                tmp[p[i].dis]++;
                if(p[i].dis>l) num2++;
                else num1++;
                tmp[p[i-k].dis]--;
                if(p[i-k].dis==l){
                    if(num2) move_right();
                    else move_left();
                }
                if(p[i-k].dis>l) num2--; 
                else num1--;
                while(num1<num2) move_right();
                while(num2<num1) move_left();
                ans+=S[l];
            }
        }
        else{
            l=p[1].dis;
            tmp[p[1].dis]++;
            for(register int i=2;i<=k;i++){
                tmp[p[i].dis]++; 
                if(p[i].dis>l) num2++;
                else num1++;
            }
            while(num1<num2-1) move_right();
            while(num2<num1+1) move_left();
            r=l+1;
            while(tmp[r]==0&&r<=n) r++;
            ans=(1.0*(S[l]+S[r]))/2.0;
        //    cout<<(1.0*S[l]+1.0*S[r])/2.0<<endl;
            for(register int i=k+1;i<=n;i++){
                tmp[p[i].dis]++;
                if(p[i].dis>l) num2++;
                else num1++;
                tmp[p[i-k].dis]--;
                if(p[i-k].dis==l){
                    if(num2) move_right();
                    else move_left();
                }
                if(p[i-k].dis>l) num2--; 
                else num1--;
                while(num1<num2-1) move_right();
                while(num2<num1+1) move_left();
                r=l+1;
                while(tmp[r]==0&&r<=n) r++;
                ans+=((1.0*(S[l]+S[r]))/2.0);
                //cout<<(1.0*S[l]+1.0*S[r])/2.0<<endl;
            }
        }
        printf("%.1lf
    ",ans);
    }
    未调完

      Game

        乍一看还以为博弈论,实际就是每个人都拿集合中最大的数,而集合中的最大值不升,如果要进集合的数大于集合最大值,拿走这个数,否则  拿走最大值并把这个数加进集合

        不要用堆维护最大值,因为单调不升,开桶~  

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,k,tmp[110000],a[110000],b[110000];
    long long sum[2];
    int main(){
        scanf("%d%d",&n,&k);
        for(register int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
        b[0]=n;
        sort(b+1,b+b[0]+1);
        b[0]=unique(b+1,b+b[0]+1)-b-1;
        for(register int i=1;i<=n;i++){
            a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b;
        }
        int p;
        while(k--){
            scanf("%d",&p);
            int l=0,cur=0;
            for(register int i=1;i<=p;i++) tmp[a[i]]++,l=l>a[i]?l:a[i];
            sum[0]=sum[1]=0;
            sum[0]=b[l];
            tmp[l]--;
            while(tmp[l]==0&&l) l--;
            for(register int i=p+1;i<=n;i++){
                cur^=1;
                if(a[i]>=l)    sum[cur]+=b[a[i]];
                else{
                    sum[cur]+=b[l];
                    tmp[l]--;
                    tmp[a[i]]++;
                    while(tmp[l]==0&&l) l--;
                }
            }
            while(l){
                cur^=1;
                sum[cur]+=b[l];
                tmp[l]--;
                while(tmp[l]==0&&l) l--;
            }
            printf("%lld
    ",sum[0]-sum[1]);
        }
    }
    View Code

       Park

        树上DP,维护两个三位DP数组,一个表示从子树中走到根,一个表示从根走向子树,撒了多少面包屑,该点撒还是不撒,合并是考虑周全

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,v,to[210000],nex[210000],head[110000],tot;
    long long f[110000][110][2],tmp[110000][110][2],sum[110000],c[110000],ans;
    void add(int x,int y){
        to[++tot]=y,nex[tot]=head[x],head[x]=tot;
    }
    void dfs(int x,int pre){
        sum[x]=c[pre];
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre) continue;
            dfs(y,x);
            sum[x]+=c[y];
        }
    }
    void DFS(int x,int pre){
        f[x][1][1]=sum[x];
        tmp[x][1][1]=sum[x];
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre) continue;
            DFS(y,x);
            for(register int j=0;j<=v;j++){
                ans=max(ans,max(tmp[x][j][0]+max(f[y][v-j][0],f[y][v-j][1]),tmp[x][j][1]+max(f[y][v-j][0],f[y][v-j][1])-c[y]));
                ans=max(ans,max(f[x][j][0]+max(tmp[y][v-j][0],tmp[y][v-j][1]),f[x][j][1]+max(tmp[y][v-j][0],tmp[y][v-j][1])));
            }
            for(register int j=0;j<=v;j++){
                if(j>0){
                    f[x][j][0]=max(f[x][j][0],f[x][j-1][0]);
                    f[x][j][1]=max(f[x][j][1],f[x][j-1][1]);
                    tmp[x][j][0]=max(tmp[x][j][0],tmp[x][j-1][0]);
                    tmp[x][j][1]=max(tmp[x][j][1],tmp[x][j-1][1]);
                }
                f[x][j][0]=max(f[x][j][0],max(f[y][j][0],f[y][j][1]));
                if(j>0) f[x][j][1]=max(f[x][j][1],max(f[y][j-1][0],f[y][j-1][1])+sum[x]-c[y]);
                tmp[x][j][0]=max(tmp[x][j][0],max(tmp[y][j][0],tmp[y][j][1]));
                if(j>0) tmp[x][j][1]=max(tmp[x][j][1],max(tmp[y][j-1][1],tmp[y][j-1][0])+sum[x]);
            }
        }
        for(register int i=0;i<=v;i++){
            ans=max(ans,max(f[x][i][1],f[x][i][0]));
            ans=max(ans,max(tmp[x][i][0],tmp[x][i][1]));
            tmp[x][i][1]-=c[pre];
            //printf("x=%d i=%d f[%d][%d][1]=%lld f[%d][%d][0]=%lld tmp[%d][%d][1]=%lld tmp[%d][%d][0]=%lld
    ",x,i,x,i,f[x][i][1],x,i,f[x][i][0],x,i,tmp[x][i][1],x,i,tmp[x][i][0]);
        }
    }
    int main(){
        scanf("%d%d",&n,&v);
        for(register int i=1;i<=n;i++) scanf("%lld",&c[i]);
        for(register int i=1,x,y;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs(1,0);
        DFS(1,0);
        printf("%lld",ans);
    }
    View Code

    模拟64

      trade好题

        反悔贪心

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    using namespace std;
    int n;
    long long ans;
    priority_queue<int>q;
    int main(){
        scanf("%d",&n);
        for(register int i=1,x;i<=n;i++){
            scanf("%d",&x);
            if(q.empty()||abs(q.top())>x) q.push(-x);
            else{
                ans+=x+q.top();
                q.pop();
                q.push(-x);
                q.push(-x);
            }
        }
        printf("%lld
    ",ans);
    }
    View Code

      sum  

        莫队

    //不要忘了大样例
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int id,Q,bl[110000],blc;
    const int mod=1e9+7;
    long long fac[110000],inv[110000],ans[110000],cet;
    struct node{
        int n,m,id;
        bool operator < (const node b)const{
            return bl[n]==bl[b.n]?(bl[m]<bl[b.m]):(bl[n]<bl[b.n]);
        }
    }q[110000];
    long long qpow(long long a,long long b){
        long long ans=1;
        while(b){
            if(b&1) ans=ans*a%mod;
            b>>=1;
            a=a*a%mod;
        }
        return ans;
    }
    int main(){
        //freopen("sum3.in","r",stdin);
        //freopen("2.out","w",stdout);
        scanf("%d%d",&id,&Q);
        blc=sqrt(100000);
        fac[0]=1;
        for(register int i=1;i<=100000;i++)
            fac[i]=fac[i-1]*i%mod,bl[i]=(i-1)/blc;
        inv[100000]=qpow(fac[100000],mod-2);
        inv[0]=1;
        for(register int i=99999;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; 
        for(register int i=1;i<=Q;i++) scanf("%d%d",&q[i].n,&q[i].m),q[i].id=i;
        sort(q+1,q+Q+1);
        int n=1,m=0;
        cet=1;
        for(register int i=1;i<=Q;i++){
            while(n<q[i].n) cet=(cet*2%mod-fac[n]*inv[m]%mod*inv[n-m]%mod)%mod,n++;
            while(m<q[i].m) m++,cet=(cet+fac[n]*inv[m]%mod*inv[n-m]%mod)%mod;
            while(m>q[i].m) cet=(cet-fac[n]*inv[m]%mod*inv[n-m]%mod)%mod,m--;
            while(n>q[i].n) n--,cet=(cet+fac[n]*inv[m]%mod*inv[n-m]%mod)%mod*inv[2]%mod;
            ans[q[i].id]=(cet+mod)%mod;
        }
        for(register int i=1;i<=Q;i++) printf("%lld
    ",ans[i]);
    }
    View Code

      building

        大模拟

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    struct Hang{
        int l,r,id;
        bool operator < (const Hang b)const{
            return (l<b.l)||(l==b.l&&r<b.r);
        }
    };
    struct Lie{
        int u,d,id;
        bool operator < (const Lie b)const{
            return (u<b.u)||(u==b.u&&d<b.d);
        }
    };
    struct node{
        int l,r,u,d,id;
        bool operator < (const node b)const{
            return (u<b.u)||(u==b.u&&l<b.l);
        }
    }w[110000];
    vector<Hang>hang[110000];
    vector<Lie>lie[110000];
    int id,n,m,k,q,fa[110000];
    long long sumh[110000],sum[110000],num[110000];
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    void search_h(Hang Lockey,int i,int e){
        int j=lower_bound(hang[e].begin(),hang[e].end(),Lockey)-hang[e].begin()-1;
        for(;j<hang[e].size();j++){
            if(hang[e][j].r<w[i].l) continue;
            if(hang[e][j].l>w[i].r) break;
            int x=find(w[i].id),y=find(hang[e][j].id);
            if(x!=y){
                num[w[i].u]--;
                fa[x]=y;
            }
        }
    }
    void search_l(Lie dog,int i,int e){
        int j=lower_bound(lie[e].begin(),lie[e].end(),dog)-lie[e].begin()-1;
        for(;j<lie[e].size();j++){
            if(lie[e][j].d<w[i].u) continue;
            if(lie[e][j].u>w[i].u) break;
            int x=find(w[i].id),y=find(lie[e][j].id);
            if(x!=y){
                num[w[i].u]--;
                fa[x]=y;
            }
        }
    }
    int main(){
        scanf("%d%d%d%d%d",&id,&n,&m,&k,&q);
        for(register int i=1,u,l,d,r;i<=k;i++){
            scanf("%d%d%d%d",&w[i].u,&w[i].l,&w[i].d,&w[i].r);w[i].id=i,fa[i]=i;
            if(w[i].u==w[i].d){
                sumh[w[i].u]+=w[i].r-w[i].l+1;
                hang[w[i].u].push_back((Hang){w[i].l,w[i].r,i});
                lie[w[i].r].push_back((Lie){w[i].u,w[i].d,i});
            }
            else{
                sum[w[i].u]++,sum[w[i].d+1]--;
                lie[w[i].l].push_back((Lie){w[i].u,w[i].d,i});
                hang[w[i].d].push_back((Hang){w[i].l,w[i].r,i});
            }
        }
        sort(w+1,w+k+1);
        for(register int i=1;i<=max(n,m);i++){
            hang[i].push_back((Hang){-5,-5,0});
            lie[i].push_back((Lie){-5,-5,0});
            sort(hang[i].begin(),hang[i].end());
            sort(lie[i].begin(),lie[i].end());
        }
        for(register int i=1;i<=n;i++)    sum[i]+=sum[i-1];
        for(register int i=1;i<=n;i++)    sum[i]+=sumh[i]+sum[i-1];
        int u,v,e;
        for(register int i=1;i<=k;i++){
            if(w[i].u==w[i].d){
                num[w[i].u]++;
                Hang Lockey=(Hang){w[i].l,w[i].r,0};
                e=w[i].u-1,search_h(Lockey,i,e);
                Lie dog=(Lie){w[i].u,w[i].u,0};
                e=w[i].l-1,search_l(dog,i,e);
                e=w[i].r+1,search_l(dog,i,e);
            }
            else{
                num[w[i].u]++;
                Lie dog=(Lie){w[i].u,w[i].u,0};
                e=w[i].l-1,search_l(dog,i,e);
                e=w[i].r+1,search_l(dog,i,e);
                Hang Lockey=(Hang){w[i].l,w[i].r,0};
                e=w[i].u-1,search_h(Lockey,i,e);
            }
        }
        for(register int i=1;i<=n;i++)    num[i]+=num[i-1];
        while(q--){
            scanf("%d%d",&u,&v);
            if(u==0) printf("%lld
    ",sum[v]);
            else printf("%lld
    ",num[v]);
        }
    }
    View Code

    模拟65

      Simple 

        不太会,听他们说跟小凯的疑惑有共通的地方----赛瓦维斯特定理,可以看这个gay的博客

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int T;
    long long n,m;
    long long q;
    long long gcd(long long a,long long b){return b?gcd(b,a%b):a;}
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%lld%lld%lld",&n,&m,&q);
            long long g=gcd(n,m);
            long long cet=q;
            if(n>m) swap(n,m);
            long long num=0;
            for(register long long i=0;i<n/g;i++){
                if(q-1ll*i*m<0) break;
                num+=((q-i*m)/n)+1;
            }
            printf("%lld
    ",cet-num+1);
        }
    }
    View Code

      

      Walk

        拆边,将一个边拆成边权的因子的多条边,按因子可以将边分成几个集合,然后建树跑DFS求直径,也可以用按秩合并并查集+树剖求LCA+结  构体封装优化+卡常轻(艰)松(难)切掉

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    int n,prm[410000],num[110],v[1100000],ans[410000],to[810000],nex[810000],head[410000],tot;
    struct BCJ{
        int root,l,r,d,dep,tim;
        void clear(int x){
            root=x,l=x,r=x,d=0,dep=1;
        }
    }bcj[410000];
    struct curtree{
        int dis,fa,son,size,top;
    }tr[410000];
    void add(int x,int y){
        to[++tot]=y,nex[tot]=head[x],head[x]=tot;
    }
    struct node{
        int f,t,w;
    }e[410000];
    vector<int>vec[1100000];
    void search(int d,int ans,int id){
        if(d==prm[0]+1){
            vec[ans].push_back(id);
            return;
        }
        search(d+1,ans,id);
        for(register int i=1;i<=num[d];i++)
            ans*=prm[d],search(d+1,ans,id);
    }
    void fenjie(int x,int id){
        prm[0]=0;
        while(x!=1){
            prm[++prm[0]]=v[x];
            int w=v[x];
            num[prm[0]]=0;
            while(v[x]==w) x/=v[x],num[prm[0]]++;
        }
        search(1,1,id);
    }
    void DFS(int x,int pre){
        tr[x].top=bcj[x].root=bcj[x].l=bcj[x].r=x;
        bcj[x].d=bcj[x].dep=0;
        tr[x].size=1;
        tr[x].fa=pre;
        tr[x].dis=tr[pre].dis+1;
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre) continue;
            DFS(y,x);
            tr[x].son=tr[tr[x].son].size>tr[y].size?tr[x].son:y;
            tr[x].size+=tr[y].size;
        }
    }
    void dfs(int x,int pre){
        if(tr[x].son) tr[tr[x].son].top=tr[x].top,dfs(tr[x].son,x);
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre||y==tr[x].son) continue;
            dfs(y,x);
        }
    }
    int lca(int x,int y){
        register int xx=tr[x].top,yy=tr[y].top;
        while(xx!=yy){
            if(tr[xx].dis>tr[yy].dis) x=tr[xx].fa,xx=tr[x].top;
            else y=tr[yy].fa,yy=tr[y].top;
        }
        return tr[x].dis<tr[y].dis?x:y;
    }
    void merge(int x,int y){
        register int u[5];
        u[1]=bcj[x].l,u[2]=bcj[x].r,u[3]=bcj[y].l,u[4]=bcj[y].r;
        if(bcj[x].dep>bcj[y].dep) bcj[x].dep=max(bcj[x].dep,bcj[y].dep+1),bcj[y].root=bcj[x].root;
        else bcj[y].dep=max(bcj[x].dep+1,bcj[y].dep),bcj[x].root=bcj[y].root;
        for(register int i=1;i<=2;i++){
            for(register int j=3;j<=4;j++){
                int len=tr[u[i]].dis+tr[u[j]].dis-2*tr[lca(u[i],u[j])].dis;
                if(len>bcj[bcj[x].root].d){
                    bcj[bcj[x].root].l=u[i],bcj[bcj[x].root].r=u[j];
                    bcj[bcj[x].root].d=len;
                }
            }
        }
    }
    int find(register int x){
        while(x!=bcj[x].root) x=bcj[x].root;
        return x;
    }
    void work(int x){
        for(register int i=0;i<vec[x].size();i++){
            register int u=vec[x][i];
            if(bcj[e[u].f].tim!=x) bcj[e[u].f].clear(e[u].f);
            if(bcj[e[u].t].tim!=x) bcj[e[u].t].clear(e[u].t);
            register int fr=find(e[u].f),tt=find(e[u].t);
            merge(fr,tt);
            bcj[fr].tim=bcj[tt].tim=x;
            ans[bcj[bcj[fr].root].d]=max(ans[bcj[bcj[fr].root].d],x);
        }
    }
    inline int read(){
        register int ret;
        register char r;
        while(r=getchar(),r<'0'||r>'9');
        ret=r^48;
        while(r=getchar(),r>='0'&&r<='9') ret=(ret<<1)+(ret<<3)+(r^48);
        return ret;
    }
    int main(){
    //    freopen("ex_walk2.in","r",stdin);
    //    freopen("1.out","w",stdout);
        n=read();
        int maxn=0;
        for(register int i=1;i<n;i++){
            e[i].f=read(),e[i].t=read(),e[i].w=read();
            add(e[i].f,e[i].t);
            add(e[i].t,e[i].f);
            maxn=max(maxn,e[i].w);
        }
        for(register int i=2;i<=maxn;i++){
            if(!v[i]) v[i]=i,prm[++prm[0]]=i;
            for(register int j=1;j<=prm[0]&&i*prm[j]<=maxn;j++){
                v[prm[j]*i]=prm[j];
                if(i%prm[j]==0) break;
            }
        }
        for(register int i=1;i<n;i++) fenjie(e[i].w,i);
        DFS(1,0);
        dfs(1,0);
        for(register int i=1;i<=maxn;i++)
            work(i);
        for(register int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
        for(register int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    }
    按秩合并并查集+树剖+结构体封装优化+卡常
    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    int n,prm[410000],num[110],v[1100000],ans[410000],to[24100000],nex[24100000],head[410000],tot,vis[410000];
    void add(int x,int y){
        to[++tot]=y,nex[tot]=head[x],head[x]=tot;
    }
    struct node{
        int f,t,w;
    }e[410000];
    vector<int>vec[1100000];
    void search(int d,int ans,int id){
        if(d==prm[0]+1){
            vec[ans].push_back(id);
            return;
        }
        search(d+1,ans,id);
        for(register int i=1;i<=num[d];i++)
            ans*=prm[d],search(d+1,ans,id);
    }
    void fenjie(int x,int id){
        prm[0]=0;
        while(x!=1){
            prm[++prm[0]]=v[x];
            int w=v[x];
            num[prm[0]]=0;
            while(v[x]==w) x/=v[x],num[prm[0]]++;
        }
        search(1,1,id);
    }
    int d;
    int dfs(int x,int pre){
        int maxn=0;
        vis[x]=1;
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre) continue;
            int w=dfs(y,x);
            d=max(maxn+w,d);
            maxn=max(maxn,w);
        }
        return maxn+1;
    }
    void work(int x){
        d=0;
        for(register int i=0;i<vec[x].size();i++){
            int y=vec[x][i];
            add(e[y].f,e[y].t);
            add(e[y].t,e[y].f);
        }
        for(register int i=0;i<vec[x].size();i++){
            int y=vec[x][i];
            if(!vis[e[y].f])
                dfs(e[y].f,0);
        }
        ans[d]=x;
        for(register int i=0;i<vec[x].size();i++){
            int y=vec[x][i];
            head[e[y].f]=head[e[y].t]=0;
            vis[e[y].f]=vis[e[y].t]=0;
        }
        tot=0;
    }
    int main(){
        scanf("%d",&n);
        for(register int i=2;i<=1000000;i++){
            if(!v[i]) v[i]=i,prm[++prm[0]]=i;
            for(register int j=1;j<=prm[0]&&i*prm[j]<=1000000;j++){
                v[prm[j]*i]=prm[j];
                if(i%prm[j]==0) break;
            }
        }
        for(register int i=1;i<n;i++){
            scanf("%d%d%d",&e[i].f,&e[i].t,&e[i].w);
            fenjie(e[i].w,i);
        }
        for(register int i=1;i<=1000000;i++)
            work(i);
        for(register int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
        for(register int i=1;i<=n;i++) printf("%d
    ",ans[i]);
    }
    正解

       Travel未填之坑

        贪心+模拟

    模拟 66

      棋盘  

        经推(打)导(表) $f[i]=f[i-1]*i+(-1)^{[i&1]}$ 没用高精他挂了 ,正解式子 

           

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,f[510];
    char a[210];
    void multi(int x){
        int tmp=0;
        for(register int i=1;i<=f[0];i++){
            tmp=f[i]*x+tmp;
            f[i]=tmp%10;
            tmp/=10;
        }
        while(tmp) f[++f[0]]=tmp%10,tmp/=10;
    }
    void jian(int x){
        f[1]--;
        for(register int i=1;i<=f[0];i++){
            if(f[i]<0) f[i]+=10,f[i+1]--;
            else break;
        }
        while(f[f[0]]==0) f[0]--;
    }
    void jia(int x){
        f[1]++;
        for(register int i=1;i<=f[0];i++){
            if(f[i]==10) f[i]=0,f[i+1]++;
            else break;
        }
        f[0]++;
        while(f[f[0]]==0) f[0]--;
    }
    int main(){
        scanf("%d",&n);
        for(register int i=1;i<=n;i++) scanf("%s",a);
        f[++f[0]]=1;
        for(register int i=3;i<=n;i++){
            multi(i);
            if(i&1) jian(1);
            else jia(1);
        }
        while(f[0]) cout<<f[f[0]],f[0]--;
    }
    View Code

       传递

        bitset 暴力水过,正解将q分正反向与p建图,判断是否是DAG

    #include<iostream>
    #include<cstdio>
    #include<bitset>
    using namespace std;
    int T,n;
    char a[2100];
    bitset<2020>P[2100],Q[2100];
    int judge(){
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++)
                if(P[i][j]==1)
                    if((P[i]&P[j])!=P[j]) return 0;
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++)
                if(Q[i][j]==1)
                    if((Q[i]&Q[j])!=Q[j]) return 0;
    
        return 1;
    }
    int main(){
        //freopen("1.in","r",stdin);
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(register int i=1;i<=n;i++){
                scanf("%s",a+1);
                P[i].reset(),Q[i].reset();
                for(register int j=1;j<=n;j++){
                    if(a[j]=='P') P[i][j]=1;
                    else if(a[j]=='Q') Q[i][j]=1;
                }
            }
            if(judge()) puts("T");
            else puts("N");
        }
    }
    bitset暴力水过

      异或神题)(未填

        比数位DP还恶心的数位DP

    模拟67

      神炎皇

        因为$ a+b|ab,a=k_1*c,b=k_2*c $所以 $a+b=(k_1+k_2)*cRightarrow ab=k_1k_2c^2 Rightarrow(k_1+k_2)|k_1k_2c $

        又因为 $ gcd(k_1,k_2)=1  Rightarrow  gcd(k_1,k_1k_2)=1,gcd(k_2,k_1k_2)=1 $所以$(k1+k2)|c且gcd(k_1,k_2)=1$

        因为$a+b<=n$所以$c(k_1+k_2)<=n$ ,因为$ c=x*(k_1+k_2)$,所以$x*(k_1+k_2)^2<=n$

        因此枚举$k_1+k_2=S$的S,那么x的个数就是$n/(S^2)$,而(k_1,k_2)的组数就是$ varphi(S) $

        所以只要求 $sumlimits_{s=2}^{sqrt(n)}varphi(s)*n/(s^2) $

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    long long n;
    int phi[11000000],prm[700000];
    int main(){
        scanf("%lld",&n);
        phi[1]=1;
        for(register int i=2;i<=10000000;i++){
            if(!phi[i]) phi[i]=i-1,prm[++prm[0]]=i;
            for(register int j=1;j<=prm[0]&&i*prm[j]<=10000000;j++){
                if(i%prm[j]==0){phi[i*prm[j]]=phi[i]*prm[j];break;}
                else phi[i*prm[j]]=phi[i]*(prm[j]-1);
            }
        }
        long long ans=0;
        for(register int i=2;i<=sqrt(n);i++){
            ans=ans+1ll*phi[i]*(n/(1ll*i*i));
        }
        printf("%lld
    ",ans);
    }
    View Code

      降雷皇

        LIS问题,树状数组维护最大值,(注意参数要读全,我AC代码因为没读入type而Wa10)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,a[110000];
    const long long mod=123456789;
    struct node{
        int maxn;
        long long num;
    }tr[110000];
    int lowbit(int x){return x&(-x);}
    node ask(int x){
        node ans=(node){0,1};
        while(x){
            if(tr[x].maxn==ans.maxn) (ans.num+=tr[x].num)%=mod;
            else if(tr[x].maxn>ans.maxn) ans=tr[x];
            x-=lowbit(x);
        }
        return ans;
    }
    void add(int x,node w){
        while(x<=100000){
            if(tr[x].maxn==w.maxn) (tr[x].num+=w.num)%=mod;
            else if(w.maxn>tr[x].maxn)tr[x]=w;
            x+=lowbit(x);
        }
    }
    int main(){
        int shabi;
        scanf("%d%d",&n,&shabi);
        for(register int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(register int i=1;i<=n;i++){
            node w=ask(a[i]-1);
            w.maxn++;
            add(a[i],w);
        }
        node ans=ask(100000);
        if(shabi) printf("%d
    %lld
    ",ans.maxn,ans.num);
        else printf("%d
    ",ans.maxn);
    }
    View Code

      幻魔皇 好题

        懒得写了,还是那个gay的幻魔皇题解

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n;
    long long sumW[5100],sumB[5100],f[5100],g[5100],ans[11000];
    const int mod=123456789;
    int main(){
        scanf("%d",&n);
        sumW[1]=sumB[2]=f[0]=1;
        for(register int i=3;i<=n;i++)
            sumW[i]=(sumW[i-1]+sumW[i-2])%mod,
            sumB[i]=(sumB[i-1]+sumB[i-2])%mod;
        for(register int i=1;i<=n;i++)
            sumW[i]=(sumW[i]+sumW[i-1])%mod,
            sumB[i]=(sumB[i]+sumB[i-1])%mod;
        for(register int i=1;i<=n;i++)
            g[i]=(g[i-1]+f[i-1])%mod,f[i]=g[i-1];
        for(register int i=1;i<=n;i++) ans[i]=(ans[i]+f[i]*sumW[n-i]%mod)%mod;
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++)
                ans[i+j]=(ans[i+j]+f[i-1]*g[j-1]%mod*sumB[n-max(i,j)]%mod)%mod;
        for(register int i=1;i<=2*n;i++) printf("%lld ",ans[i]%mod);
    }
    View Code

    模拟68

      d 

        肯定是删够m个才有最大的交集,枚举删i个a最小的,那么删去m-i个b最小的,a用sort排序,b放堆里面

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    int T,n,m,v[110000];
    struct node{
        int id,a,b;
        bool operator < (const node x)const{
            return a<x.a;
        }
    }w[110000];
    struct Node{
        int id,a,b;
        bool operator < (const Node x)const{
            return (b>x.b)||(b==x.b&&a>x.a);
        }
    };
    priority_queue<Node>q;
    int main(){
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            for(register int i=1;i<=n;i++){
                scanf("%d%d",&w[i].a,&w[i].b),w[i].id=i;
            }
            sort(w+1,w+n+1);
            long long ans=0,minna=w[m+1].a;
            for(register int i=m+1;i<=n;i++) q.push((Node){w[i].id,w[i].a,w[i].b});
            for(register int i=m;i>=0;i--){
                ans=max(ans,minna*q.top().b);
                if(w[i].b>=q.top().b) minna=min(minna,1ll*w[i].a),q.pop(),q.push((Node){w[i].id,w[i].a,w[i].b});
            }
            while(q.size())q.pop();
            printf("%lld
    ",ans);
        }
    }
    View Code

      e 好题

        树上主席树或主席树上树(^_^)维护一个点到根的那条链上的点权,所要查的联通块其实就是所有pi 到他们lca 的链的并

        用pi的主席树减lca的父亲的主席树,查询r的前驱和后继

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,q,type,a[110000],fa[110000][19],dis[110000];
    int to[210000],nex[210000],head[110000],tot;
    int root[110000],ls[8100000],rs[8100000],num[8100000],cet;
    int p[110000];
    const int upw=1e9;
    void add(int x,int y){
        to[++tot]=y,nex[tot]=head[x],head[x]=tot;
    }
    void add_point(int &t1,int t2,int l,int r,int x){
        if(!t1) t1=++cet;
        if(l==r){
            num[t1]=num[t2]+1;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x){
            add_point(ls[t1],ls[t2],l,mid,x);
            rs[t1]=rs[t2];
        }
        else{
            add_point(rs[t1],rs[t2],mid+1,r,x);
            ls[t1]=ls[t2];
        }
        num[t1]=num[ls[t1]]+num[rs[t1]];
    }
    int ask_max(int t1,int t2,int l,int r,int L,int R){
        if(num[t1]==num[t2]) return 0;
        if(l==r) return l; 
        int mid=(l+r)>>1,ans=0;
        if(mid<R) ans=ask_max(rs[t1],rs[t2],mid+1,r,L,R);
        if(ans) return ans;
        if(mid>=L) ans=ask_max(ls[t1],ls[t2],l,mid,L,R);
        if(ans) return ans;
        return 0;
    }
    int ask_min(int t1,int t2,int l,int r,int L,int R){
        if(num[t1]==num[t2]) return 0;
        if(l==r) return l; 
        int mid=(l+r)>>1,ans=0;
        if(mid>=L) ans=ask_min(ls[t1],ls[t2],l,mid,L,R);
        if(ans) return ans;
        if(mid<R) ans=ask_min(rs[t1],rs[t2],mid+1,r,L,R);
        if(ans) return ans;
        return 0;
    }
    void dfs(int x,int pre){
        fa[x][0]=pre;
        dis[x]=dis[pre]+1;
        add_point(root[x],root[pre],1,upw,a[x]);
        for(register int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for(register int i=head[x];i;i=nex[i]){
            int y=to[i];
            if(y==pre) continue;
            dfs(y,x);
        }
    }
    int lca(int x,int y){
        if(x==0) return y;
        if(dis[x]>dis[y]) swap(x,y);
        int i=0;
        for(;(1<<i)<=dis[y];i++);
        for(register int j=i;j>=0;j--)
            if(dis[fa[y][j]]>=dis[x])
                y=fa[y][j];
        if(x==y) return x;
        for(register int j=i;j>=0;j--)
            if(fa[y][j]!=fa[x][j])
                y=fa[y][j],
                x=fa[x][j];
        return fa[x][0];
    }
    int main(){
        scanf("%d%d%d",&n,&q,&type);
        for(register int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(register int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
        dfs(1,0);
        long long r,k,las=0;
        while(q--){
            scanf("%lld%lld",&r,&k);
            int lc=0;
            las%=n;
            for(register int i=1;i<=k;i++){
                scanf("%d",&p[i]);
                p[i]=(p[i]-1+1ll*las*type%n)%n+1;
                lc=lca(lc,p[i]);
            }
            las=0x7ffffffffffff;
            for(register int i=1;i<=k;i++){
                int w1=ask_max(root[p[i]],root[fa[lc][0]],1,upw,1,r);
                int w2=ask_min(root[p[i]],root[fa[lc][0]],1,upw,r,upw);
                if(w1&&w2) las=min(las,min(1ll*r-w1,1ll*w2-r));
                else if(w2) las=min(las,1ll*w2-r);
                else las=min(las,1ll*r-w1);
            }
            printf("%lld
    ",las);
        }
    }
    View Code

      f神题)(未填

        前i-1高位相同,第i为不同,那么这两个数的大小关系取决于res的第i位,即每一位i的贡献之间没有影响

        01trie树求每一位是0或1的贡献,可以暴力算出每一个res的贡献排序,这样可以拿到55分

        正解是二分f[res],求出有p-1个f值小于f[res],即满足f[res]是第p小

        然后求出最小的res

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,k,p;
    int num[30000000],to[30000000][2],tot=1,t[31000000];
    long long sum[35][2];
    struct node{
        int id;
        long long sum;
        bool operator < (const node b)const{
            return (sum<b.sum)||(sum==b.sum&&id<b.id);
        }
    }w[50000000];
    void add(int x){
        int root=1,c[35];
        for(register int i=0;i<k;i++,x>>=1) c[i]=x&1;
        for(register int i=k-1;i>=0;i--){
            if(to[root][c[i]]==0) to[root][c[i]]=++tot;
            sum[i][c[i]]+=num[to[root][c[i]^1]];
            root=to[root][c[i]];
            num[root]++;
        } 
    }
    int main(){
        scanf("%d%d%d",&n,&k,&p);
        for(register int i=1,x;i<=n;i++){
            scanf("%d",&x);
            add(x);
        }
        long long cet=0;
        for(register int i=0;i<k;i++){
            t[1<<i]=i;
            sum[i][1]=sum[i][1]-sum[i][0],cet+=sum[i][0];
        }
        w[0].id=0,w[0].sum=cet;
        for(register int i=1;i<(1<<k);i++){
            w[i].sum=w[i^(i&(-i))].sum+sum[t[i&(-i)]][1];
            w[i].id=i;
        }
        nth_element(w+0,w+p-1,w+(1<<k));
        printf("%lld %d
    ",w[p-1].sum,w[p-1].id);
    }
    55分暴力

    模拟69

      chess

        $O(n^4log)$DP,预处理转移系数,去掉log

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,num;
    long long f[110][11000],C[110][110],dp[110][11000];
    long long fac[11000];
    long long m;
    const int mod=1e9+7;
    long long qpow(long long a,long long b){
        long long ans=1;
        while(b){
            if(b&1) ans=ans*a%mod;
            b>>=1;
            a=a*a%mod;
        }
        return ans%mod;
    }
    int main(){
        scanf("%d%lld%d",&n,&m,&num);
        if(m==n){
            fac[0]=1;
            for(register int i=1;i<=n*n;i++) fac[i]=fac[i-1]*i%mod;
            printf("%lld
    ",fac[n*n]*qpow(fac[num]*fac[n*n-num]%mod,mod-2)%mod);
            return 0;
        }
        for(register int i=0;i<=n;i++){
            C[i][0]=1;
            for(register int j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
        if(num>n*n/2) num=n*n-num;
        for(register int i=1;i<=n;i++){
            long long tim=m/n;
            if(m%n>=i) tim++;
            tim%=(mod-1);
            for(register int j=0;j<=num;j++){
                dp[i][j]=qpow(C[n][j],tim);
            }
        }
        f[0][0]=1;
        for(register int i=1;i<=n;i++){
            for(register int j=0;j<=num;j++){
                for(register int k=0;k<=j;k++){
                    f[i][j]=(f[i][j]+f[i-1][k]*dp[i][j-k]%mod)%mod;
                }
            }
        }
        printf("%lld
    ",f[n][num]);
    }
    所谓n^5,实际特判A掉的代码

      array好题

        单调栈维护单调不下降序列,如果当前走到i且弹完栈插入i,那么栈中元素k到i之间没有比a[k]更小的元素,所以只需要找k到i之间最大的  元素的位置s,来用s-k+1更新答案

        可以用一个数组maxn[k]记录k到当前点之间最大的元素的位置,显然栈顶的maxn可以更新栈内的所有元素的maxn,(top出栈的时候,和下  一个取max传下去即可)

        所以是$O(1)$更新,总复杂度$O(n)$

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,a[11000000],st[11000000],maxn[11000000];
    inline int read(){
        register int ret;
        register char r;
        while(r=getchar(),r<'0'||r>'9');
        ret=r^48;
        while(r=getchar(),r>='0'&&r<='9') ret=(ret<<1)+(ret<<3)+(r^48);
        return ret;
    }
    int main(){
        //freopen("2.in","r",stdin);
        //freopen("2.out","w",stdout);
        n=read();
        for(register int i=1;i<=n;i++) a[i]=read();
        int ans=0;
        for(register int i=1;i<=n+1;i++){
            while(st[0]&&a[st[st[0]]]>a[i]){
                if(a[maxn[st[0]-1]]<=a[maxn[st[0]]]) maxn[st[0]-1]=maxn[st[0]];
                ans=max(ans,maxn[st[0]]-st[st[0]]+1);
                maxn[st[0]]=0;
                st[0]--;
            }
            if(i==n+1) break;
            st[++st[0]]=i;
            maxn[st[0]]=i;
        }
        printf("%d
    ",ans);
    }
    View Code

      ants好题

        莫队+线段树,但是会TLE50

        可以用回滚莫队+链表思想

        这里用到了一个更强大的莫队——回滚莫队:

          如果待查区间在同一个块或在两个相邻的块,暴力扫,

          如果待查区间在不同的块(块不相邻)里,将整块暴力扫进去,然后在这基础上向左向右扩展不到一个块的部分,统计完答案后delet恢    复原来的基础状态(整块的状态)

          特殊的,我们把块编号[1,n],对于当前基础状态包含块[l,r-1],而当前整块有[l,r],那么在原状态的基础上加上r 这个块的贡献,并    把块[l,r]的贡献作为新的基础状态

          非常优雅

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,m,blc,bl[110000],a[110000],ans[110000];
    int L[110000],R[110000],st[110000],top,upw,cet;
    struct node{
        int l,r,id;
        char operator < (const node b)const{
            return bl[l]==bl[b.l]?(r<b.r):(bl[l]<bl[b.l]);
        }
    }q[110000];
    inline int read(){
        register int ret;
        register char r;
        while(r=getchar(),r<'0'||r>'9');
        ret=r^48;
        while(r=getchar(),r>='0'&&r<='9') ret=(ret<<1)+(ret<<3)+(r^48);
        return ret;
    }
    void add(int x){
        L[x]=R[x]=x;
        if(L[x-1]) L[x]=min(L[x],L[x-1]);
        if(R[x+1]) R[x]=max(R[x],R[x+1]);
        if(L[x-1]) R[L[x-1]]=R[x];
        if(R[x+1]) L[R[x+1]]=L[x];
        st[++top]=x;
        cet=max(cet,R[x]-L[x]+1);
    }
    void del(){
        while(top>upw){
            int x=st[top--];
            if(L[x]==x&&R[x]==x) L[x]=R[x]=0;
            else if(L[x]==x){
                L[R[x]]=x+1;
                R[x+1]=R[x];
                L[x]=R[x]=0;
            }
            else if(R[x]==x){
                R[L[x]]=x-1;
                L[x-1]=L[x];
                L[x]=R[x]=0;
            }
            else{
                L[R[x]]=x+1;
                R[L[x]]=x-1;
                L[x-1]=L[x];
                R[x+1]=R[x];
                L[x]=R[x]=0;
            }
        }
    }
    int main(){
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        n=read(),m=read();
        blc=sqrt(n);
        for(register int i=1;i<=n;i++) a[i]=read(),bl[i]=(i-1)/blc+1;
        for(register int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
        sort(q+1,q+m+1);
        int l=0,r=0;
        for(register int i=1;i<=m;i++){
            if(bl[q[i].r]-bl[q[i].l]<=1){
                cet=upw=0;
                del();
                for(register int j=q[i].l;j<=q[i].r;j++)
                    add(a[j]);
                ans[q[i].id]=cet;
                del();
                l=r=0;
            }
            else{
                if(l!=bl[q[i].l]*blc){
                    upw=cet=0;
                    del();
                    r=l=bl[q[i].l]*blc,add(a[l]); 
                }
                while(r<(bl[q[i].r]-1)*blc) ++r,add(a[r]);
                upw=top;
                int las=cet;
                while(l>q[i].l) --l,add(a[l]);
                while(r<q[i].r) ++r,add(a[r]);
                ans[q[i].id]=cet;
                cet=las;
                del();
                l=bl[q[i].l]*blc,r=(bl[q[i].r]-1)*blc;
            }
        }
        for(register int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    }
    View Code

    总结:

        好几天没写博客,一下子全整完真的挺累的。

         不过发现其实时不时的回头看看做过的题也挺好,收获也蛮多的。

         还有30多天就要CSP-S了,希望我能多进步一点儿,但愿能留下来吧。

  • 相关阅读:
    Java中使用Jedis连接Redis对Hash进行操作的常用命令
    Java中使用Jedis连接Redis对Set进行操作的常用命令
    Java中使用Jedis连接Redis对List进行操作的常用命令
    Android中获取定位经纬度信息
    Java中使用Jedis连接Redis对String进行操作的常用命令
    Java中使用Jedis连接Redis对Key进行操作的常用命令
    Java中使用Jedis连接池连接Redis数据库流程
    Java中使用Jedis连接Redis数据库流程
    Java中使用Jedis连接Redis服务端时提示:JedisConnectionException: Failed connecting
    调用百度翻译对句子进行翻译
  • 原文地址:https://www.cnblogs.com/heoitys/p/11660244.html
Copyright © 2020-2023  润新知