2022国庆xcpc刷题训练

预期题单

9月30号

Codeforces Beta Round #19 D

数组离散化unique的时候是伪删除会把重复元素放到数组后面
这道题采取树套树的思想,线段树套一个set

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
#define ls u<<1
#define rs u<<1|1
typedef pair<int,int>PII;
int T,x,y,cnt,a[N],b[N],s[N*4];
string op;
set<int>S[N*4];
struct Query{
    
    
    string op;
    int x,y;
}Q[N];
void pushup(int u){
    
    s[u]=max(s[ls],s[rs]);}
int len;
void modify(int u,int x,int y,int op=1,int l=0,int r=len){
    
    
    if(l==r){
    
    
        if(op==1)S[u].insert(y);
        else S[u].erase(y);
        if(S[u].size()==0)s[u]=0;
        else s[u]=*(--S[u].end());
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)modify(ls,x,y,op,l,mid);
    else modify(rs,x,y,op,mid+1,r);
    pushup(u);
}
auto p=make_pair(-1,-1);
PII q(int u,int x,int y,int l=0,int r=len){
    
    
    if(r<x)return p;
    if(s[u]<y)return p;
    if(l==r)return make_pair(l,*S[u].lower_bound(y));
    int mid=l+r>>1;
    auto L=q(ls,x,y,l,mid);
    if(L==p)return q(rs,x,y,mid+1,r);
    else return L;
}
int mp[N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    for(int i=1;i<=T;i++){
    
    
        cin>>op>>x>>y;
        Q[i]={
    
    op,x,y};
        a[cnt++]=x,a[cnt++]=y;
    }
    sort(a,a+cnt);
    len=unique(a,a+cnt)-a;
    for(int i=1;i<=T;i++){
    
    
        op=Q[i].op,x=Q[i].x,y=Q[i].y;
        int k=1;
        if(op=="remove")k=-1;
        if(op=="find"){
    
    
            x=lower_bound(a,a+len,x+1)-a;
            y=lower_bound(a,a+len,y+1)-a;
            auto t=q(1,x,y);
            if(t==p)cout<<-1<<'\n';
            else cout<<a[t.first]<<" "<<a[t.second]<<'\n';
        }
        else{
    
    
            x=lower_bound(a,a+len,x)-a;
            y=lower_bound(a,a+len,y)-a;
            modify(1,x,y,k);
        }
    }
}

Problem - 85D - Codeforces

向集合里add,del数
第三个操作,求将集合里的数排序后的∑(a[i%5==3])


/*
---i---|--j----
   i    cnt[ls]+j
   i是ls最后一个mod5的点,j是rs第一个mod5的点
   所以他们之间距离mod5==0
   cnt+j-i=0
   j=i-cnt%5
*/
#include<bits/stdc++.h>
#define int long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N=1e5+10;
int T,n,m,len,a[N];
string op[N];
int x[N];
int cnt[N*4],sum[N*4][5];
void pushup(int u){
    
    
    cnt[u]=cnt[ls]+cnt[rs];
    for(int i=0;i<5;i++){
    
    
        int j=((i-cnt[ls])%5+5)%5;
        sum[u][i]=sum[ls][i]+sum[rs][j];
    }
}
void modify(int u,int x,int op=1,int l=0,int r=len-1){
    
    
    if(l==r){
    
    
        cnt[u]+=op;
        sum[u][1]+=op*a[x];
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)modify(ls,x,op,l,mid);
    else modify(rs,x,op,mid+1,r);
    pushup(u);
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        cin>>op[i];
        if(op[i]=="add"){
    
    
            cin>>x[i];
            a[m++]=x[i];
        }
        if(op[i]=="del")cin>>x[i];
    }
    sort(a,a+m);
    len=unique(a,a+m)-a;
    // for(int i=0;i<len;i++)cout<<"a["<<i<<"]="<<a[i]<<'\n';
    for(int i=1;i<=n;i++){
    
    
        if(op[i]=="add"){
    
    
            int t=lower_bound(a,a+len,x[i])-a;
            modify(1,t,+1);
        }
        if(op[i]=="del"){
    
    
            int t=lower_bound(a,a+len,x[i])-a;
            modify(1,t,-1);
        }
        if(op[i]=="sum")cout<<sum[1][3]<<'\n';
    }
}

10月1号

Codeforces Beta Round #87 (Div. 1 Only)E

n个路m个任务,修建第i个路有ci的代价,如果l-r的路都是修建好的会得到x的利润,求最大利润
设f【i】表示前i段路的最大代价
这道题最难的就是状态转移的设计
建议自己不看题解再做一遍,挺经典的值得三刷

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef pair<int,int>PII;
#define l first
#define v second
#define ls u<<1
#define rs u<<1|1
#define int long long
int f[N],lazy[N*4],sum[N*4],c[N];
int n,m;
vector<PII>v[N];
void pushdown(int u){
    
    
    sum[ls]+=lazy[u],lazy[ls]+=lazy[u];
    sum[rs]+=lazy[u],lazy[rs]+=lazy[u];
    lazy[u]=0;
}
int pushup(int u){
    
    
    sum[u]=max(sum[ls],sum[rs]);
}
void modify(int u,int ql,int qr,int v,int l=0,int r=n){
    
    
    if(ql>r||qr<l)return;
    if(ql<=l&&r<=qr){
    
    
        sum[u]+=v;
        lazy[u]+=v;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    modify(ls,ql,qr,v,l,mid);
    modify(rs,ql,qr,v,mid+1,r);
    pushup(u);
}
int query(int u,int ql,int qr,int l=0,int r=n){
    
    
    if(ql>r||qr<l)return 0;
    if(ql<=l&&r<=qr)return sum[u];
    int mid=l+r>>1;
    pushdown(u);
    return max(query(ls,ql,qr,l,mid),query(rs,ql,qr,mid+1,r));
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>c[i];
    for(int i=1;i<=m;i++){
    
    
        int l,r,x;
        cin>>l>>r>>x;
        v[r].push_back({
    
    l,x});
    }
    for(int i=1;i<=n;i++){
    
    
        modify(1,0,i-1,-c[i]);
        for(auto &[l,x]:v[i]){
    
    
            modify(1,0,l-1,x);
        }
        f[i]=max(query(1,0,i-1),f[i-1]);
        modify(1,i,i,f[i]);
    }
    cout<<f[n];
}


Codeforces Beta Round #28 (Codeforces format)B

a【】=1 ~ n
给一个d数组表示第i个数字可以跟距离为d【i】的数字交换
给一个b数组表示a是否可以变成b
考点–flyod求闭包

#include<bits/stdc++.h>
using namespace std;
const int N=110;
typedef pair<int,int>PII;
int d[N],b[N],f[N][N],n;

signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++)cin>>d[i];
    for(int i=1;i<=n;i++){
    
    
        f[i][i]=1;
        if(i-d[i]>=1)f[i][i-d[i]]=f[i-d[i]][i]=1;
        if(i+d[i]<=n)f[i][i+d[i]]=f[i+d[i]][i]=1;
    }
    for(int k=1;k<=n;k++){
    
    
        for(int i=1;i<=n;i++){
    
    
            for(int j=1;j<=n;j++){
    
    
                f[i][j]|=f[i][k]&f[k][j];
            }
        }
    }
    for(int i=1;i<=n;i++){
    
    
        if(f[i][b[i]]==0){
    
    
            cout<<"NO";
            return 0;
        }
    }
    cout<<"YES";
}

Codeforces Beta Round #36E

欧拉路径是找到一条路径覆盖所有的边
这道题是让你用两条路径覆盖所有的边求方案

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=2*N;
int m,p[N],h[N],e[M],ne[M],vis[M],idx,d[N],ans[M],c;
map<int,int>mp;
void add(int a,int b){
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int find(int x){
    
    
    if(p[x]==x)return x;
    return p[x]=find(p[x]);
}
void dfs(int u){
    
    
    for(int i=h[u];~i;i=ne[i]){
    
    
        int j=e[i];
        if(vis[i])continue;
        vis[i]=vis[i^1]=1;
        dfs(j);
        ans[++c]=i;
    }
}

signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    cin>>m;
    if(m==1){
    
    cout<<"-1";return 0;}
    for(int i=0;i<=10000;i++)p[i]=i,h[i]=-1;
    for(int i=1;i<=m;i++){
    
    
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
        d[a]++,d[b]++;
        if(find(a)==find(b))continue;
        p[find(a)]=find(b);
    }
    //用两条路径覆盖全部的边
    /*
    回顾欧拉路径的定义:
    有向图:有两个点出度=入度+1,入度=出度+1,其他点出度=入度
    无向图:有两个点度数为奇数,其他点度数为偶数
    
    回顾欧拉回路的定义:
    有向图:出度=入度
    无向图:所有度数均为偶数
    
    那么这道题就是两个欧拉路径无向图,所以点度数为奇数个数只能是{0,2,4}
    分类讨论如果是1个连通分量或者两个连通分量
    
    上述分析均不考虑孤立点
    */
    int cnt=0;
    for(int i=1;i<=10000;i++){
    
    
        if(d[i]==0)continue;
        mp[find(i)]+=d[i]&1;
        if(find(i)==i)cnt++;
    }
    if(cnt>2){
    
    cout<<"-1";return 0;}
    if(cnt==2){
    
    //两个欧拉路径
        for(auto t:mp){
    
    
            if(t.second==0||t.second==2)continue;
            cout<<"-1";
            return 0;
        }
        for(auto t:mp){
    
    
            int u=t.first;
            for(int i=1;i<=10000;i++){
    
    
                if(find(i)==t.first&&d[i]&1)
                {
    
    u=i;break;}
            }
            c=0;
            dfs(u);
            cout<<c<<'\n';
            for(int i=1;i<=c;i++)cout<<ans[i]/2+1<<"\n";
        }
    }
    if(cnt==1){
    
    
        auto t=*mp.begin();
        if(t.second==0||t.second==2){
    
    
            int u=t.first;
            for(int i=1;i<=10000;i++){
    
    
                if(find(i)==t.first&&d[i]&1)
                {
    
    u=i;break;}
            }
            c=0;
            dfs(u);
            cout<<1<<'\n';
            cout<<ans[1]/2+1<<'\n';
            cout<<c-1<<'\n';
            for(int i=2;i<=c;i++)cout<<ans[i]/2+1<<" ";
        }
        else if(t.second==4){
    
    
            vector<int>ji;
            for(int i=1;i<=10000;i++){
    
    
                if(d[i]==0)continue;
                if(d[i]&1)ji.push_back(i);
            }
            add(ji[0],ji[1]),add(ji[1],ji[0]);
            c=0;
            dfs(ji[2]);
            int x;
            for(int i=1;i<=c;i++){
    
    
                // cout<<"ans["<<i<<"]="<<ans[i]<<" ";
                if(ans[i]>=2*m)x=i;
            }
            // cout<<'\n';
            // return 0;
            cout<<x-1<<'\n';
            for(int i=1  ;i< x;i++)cout<<ans[i]/2+1<<" ";
            cout<<'\n';
            cout<<c-x<<'\n';
            for(int i=x+1;i<=c;i++)cout<<ans[i]/2+1<<' ';
        }
        else{
    
    
            cout<<-1;
            return 0;
        }
        
    }
    
}

Codeforces Beta Round #88C

找一个len=3的环

#include<bits/stdc++.h>
using namespace std;
const int N=5500;
int n;
char s[N][N];
int to[N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>s[i]+1;
    for(int i=1;i<=n;i++){
    
    
        for(int j=1;j<=n;j++){
    
    
            if(s[i][j]=='1')to[j]=i;
        }
    }
    for(int i=1;i<=n;i++){
    
    
        for(int j=1;j<=n;j++){
    
    
            //j-i i->x x->j
            if(s[j][i]=='1'&&s[i][to[j]]=='1'){
    
    
                cout<<j<<" "<<i<<" "<<to[j];
                return 0;
            }
        }
    }
    cout<<-1;
}

10月8号

flyod

求从1号点到n号点的最短路径,每次可以选择一条边a-b断开并connect a-c

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=550,M=1e6+10;
int T,n,f[N][N],m,a[M],b[M],c[M];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n>>m;
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
    
    
            if(i==j)f[i][j]=0;
            else f[i][j]=1e9;
        }
        for(int i=1;i<=m;i++){
    
    
            cin>>a[i]>>b[i]>>c[i];
            f[a[i]][b[i]]=f[b[i]][a[i]]=1;
        }
        for(int k=1;k<=n;k++){
    
    
            for(int i=1;i<=n;i++){
    
    
                for(int j=1;j<=n;j++){
    
    
                    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
                }
            }
        }
        int ans=1e18;
        for(int i=1;i<=m;i++){
    
    
            int u=a[i];
            int v=b[i];
            int w=c[i];
            ans=min(ans,w*(f[1][u]+1+f[v][n]));
            ans=min(ans,w*(f[1][v]+1+f[u][n]));
            for(int x=1;x<=n;x++){
    
    
                ans=min(ans,w*(f[1][x]+f[x][n]+min(f[u][x],f[v][x])+2));
            }
        }
        cout<<ans<<'\n';
    }
}

单调栈优化dp

将序列分成k段(k=1~n)
每一段的权重为max ai
求min ∑序列分成k段

#include<bits/stdc++.h>
using namespace std;
const int N=8080;
int f[N][N],stk[N],top,sum[N],n,a[N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)f[0][i]=1e9,sum[i]=1e9;
    for(int i=1;i<=n;i++){
    
    
        top=0;
        f[i][top]=1e9;
        for(int j=i;j<=n;j++){
    
    
            sum[j]=f[i-1][j-1];
            while(top&&a[stk[top]]<=a[j]){
    
    
                sum[j]=min(sum[j],sum[stk[top--]]);
            }
            
            f[i][j]=min(f[i][stk[top]],sum[j]+a[j]);
            stk[++top]=j;
        }
        cout<<f[i][n]<<'\n';
    }
}

mex on tree

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>g[N];
int n,a[N],sz[N],ans[N],f[N];
/*
找到最大连通块使得mex=0~n
*/
void dfs(int u,int fa=0){
    
    
    sz[u]=1;
    f[u]=a[u];
    int ma=0;
    for(auto j:g[u]){
    
    
        if(j==fa)continue;
        dfs(j,u);
        ma=max(ma,sz[j]);
        f[u]=min(f[u],f[j]);
        sz[u]+=sz[j];
    }
    if(a[u]==0){
    
    ans[0]=ma;return;}
    if(f[u]<a[u])ans[a[u]]=0;
    else ans[a[u]]=n-sz[u];
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    int r=1;
    for(int i=1;i<=n;i++){
    
    
        cin>>a[i];
        if(a[i]==0)r=i;
    }
    for(int i=2;i<=n;i++){
    
    
        int fa;
        cin>>fa;
        g[fa].push_back(i);
        g[i].push_back(fa);
    }
    dfs(r);
    for(int k=0;k<n;k++)cout<<ans[k]<<" ";
    cout<<n;
}

直方图最大面积

class Solution {
    
    
public:
static const int N=2e5+10;
int w[N],ans,stk[N],ls[N],rs[N],sz[N],n;
void build(){
    
    
    for(int i=1;i<=n;i++)ls[i]=rs[i]=sz[i]=0;
    int top=0;
    for(int i=1;i<=n;i++){
    
    
        int k=top;
        while(k&&w[i]<=w[stk[k]])k--;
        if(k)rs[stk[k]]=i;
        if(k<top)ls[i]=stk[k+1];
        stk[++k]=i,top=k;
    }
}
void dfs(int u){
    
    
    if(ls[u])dfs(ls[u]);
    if(rs[u])dfs(rs[u]);
    sz[u]=sz[ls[u]]+sz[rs[u]]+1;
    ans=max(ans,sz[u]*w[u]);
}

    int largestRectangleArea(vector<int>& h) {
    
    
        n=h.size();
        for(int i=1;i<=n;i++)w[i]=h[i-1];
        build();
        dfs(stk[1]);
        return ans;
    }
};

笛卡尔树

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e6+10;
int n,a[N],b[N],ls[N],rs[N],sz[N],ans=-1e18,stk[N];
void build(){
    
    
    int top=0;
    for(int i=1;i<=n;i++){
    
    
        int k=top;
        while(k&&a[i]<=a[stk[k]])k--;
        if(k)rs[stk[k]]=i;
        if(k<top)ls[i]=stk[k+1];
        stk[++k]=i,top=k;
    }
}
int lmax[N],rmax[N];
int lmin[N],rmin[N];
int sum[N];
void dfs(int u){
    
    
    if(ls[u])dfs(ls[u]);
    if(rs[u])dfs(rs[u]);
    sum[u]=sum[ls[u]]+b[u]+sum[rs[u]];
    lmax[u]=max(lmax[ls[u]],sum[ls[u]]+b[u]+lmax[rs[u]]);
    lmin[u]=min(lmin[ls[u]],sum[ls[u]]+b[u]+lmin[rs[u]]);
    rmax[u]=max(rmax[rs[u]],sum[rs[u]]+b[u]+rmax[ls[u]]);
    rmin[u]=min(rmin[rs[u]],sum[rs[u]]+b[u]+rmin[ls[u]]);
    if(a[u]>0)ans=max(ans,a[u]*(rmax[ls[u]]+b[u]+lmax[rs[u]]));
    else ans=max(ans,a[u]*(rmin[ls[u]]+b[u]+lmin[rs[u]]));
    
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    build();
    dfs(stk[1]);
//     cout<<"a["<<stk[1]<<"]="<<a[stk[1]]<<'\n';
    cout<<ans;
}

Life is a Game

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=2e5+10;
int f[N][21],ma[N][21],a[N],b[N],n,m,q,u,k,p[N];
struct node{
    
    
    int u,vv,w;
    bool operator<(const node&t){
    
    
        return w<t.w;
    }
};
vector<node>v;
vector<int>g[N];
int find(int x){
    
    
    if(p[x]==x)return p[x];
    return p[x]=find(p[x]);
}
void dfs(int u,int fa=0){
    
    
    f[u][0]=fa;
    for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1];
    for(auto j:g[u]){
    
    
        dfs(j,u);
        a[u]+=a[j];
    }
}
void dfs2(int u,int fa=0){
    
    
    ma[u][0]=b[fa]-a[u];
    for(int i=1;i<=20;i++){
    
    
        ma[u][i]=max(ma[u][i-1],ma[f[u][i-1]][i-1]);
    }
    for(auto j:g[u]){
    
    
        dfs2(j,u);
    }
}

signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m>>q;
    for(int i=1;i<=n+m;i++)p[i]=i;
    for(int i=1;i<=n;i++)cin>>a[i];
    while(m--){
    
    
        int u,vv,w;
        cin>>u>>vv>>w;
        v.push_back({
    
    u,vv,w});
    }
    sort(v.begin(),v.end());
    for(auto t:v){
    
    
        int u=t.u;
        int v=t.vv;
        int w=t.w;
        u=find(u),v=find(v);
        if(u==v)continue;
        n++;
        b[n]=w;
        p[u]=p[v]=n;
        g[n].push_back(u),g[n].push_back(v);
    }
    dfs(n);
    b[0]=2e9+1;
    dfs2(n);
    while(q--){
    
    
        cin>>u>>k;
        for(int i=20;i>=0;i--){
    
    
            if(k>=ma[u][i])u=f[u][i];
        }
        cout<<a[u]+k<<'\n';
    }
}

华华开始学信息学

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,tr[N],m,d[N];
void add(int x,int c){
    
    
    for(int i=x;i<=n;i+=i&-i)tr[i]+=c;
}
int sum(int x){
    
    
    if(x==0)return 0;
    int ans=0;
    for(int i=x;i;i-=i&-i)ans+=tr[i];
    return ans;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    while(m--){
    
    
        int op;
        cin>>op;
        if(op==1){
    
    
            int D,K;
            cin>>D>>K;
            if(D>400)for(int i=D;i<=n;i+=D)add(i,K);
            if(D<=400) d[D]+=K;
        }
        else{
    
    
            int l,r;
            cin>>l>>r;
            int ans=sum(r)-sum(l-1);
            for(int i=1;i<=400;i++)ans+=(r/i-(l-1)/i)*d[i];
            cout<<ans<<'\n';
        }
    }
}

牛客挑战赛32E树上逆序对

算逆序对的时候,按照权值从小到大的dfs序去插入和查询计数
本题其实就是当把一个顺逆序对,某个权值变负所造成的影响
对祖宗造成影响 ,对儿子也造成影响
开两课树分别计算,那么贡献就是01背包的放与不放
注意细节祖宗树,插入的时候就是dfn[u],1 和 dfn[u]+sz[u]-1,-1
查询的时候就是query dfn[u]

子节点树,插入的时候dfn 1,查询的时候就是dfn到dfn+sz-1

#include<bits/stdc++.h>
#define ls u<<1
#define rs u<<1|1 
using namespace std;
const int N=1e5+10;
int n,dfn[N],sz[N];
vector<int>g[N];
struct tree{
    
    
    int a[N*4];
    tree(){
    
    memset(a,0,sizeof a);}
    void pushup(int u){
    
    
        a[u]=a[ls]+a[rs];
    }
    void modify(int u,int x,int v,int l=0,int r=n){
    
    
        if(l==r){
    
    
            a[u]+=v;
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)modify(ls,x,v,l,mid);
        else modify(rs,x,v,mid+1,r);
        pushup(u);
    }
    int query(int u,int ql,int qr,int l=0,int r=n){
    
    
        if(ql<=l&&r<=qr)return a[u];
        if(ql>r||qr<l)return 0;
        int mid=(l+r)>>1;
        return query(ls,ql,qr,l,mid)+query(rs,ql,qr,mid+1,r);
    }
    
}T[2];
struct node{
    
    
    int v,i;
}a[N];
int idx,o[N];
void dfs(int u,int fa=0){
    
    
    dfn[u]=++idx;
    sz[u]=1;
    for(auto j:g[u]){
    
    
        if(j==fa)continue;
        dfs(j,u);
        sz[u]+=sz[j];
    }
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        cin>>a[i].v;
        a[i].i=i;
    }
    sort(a+1,a+1+n,[&](node x,node y){
    
    
        return x.v<y.v;
    });
//     for(int i=1;i<=n;i++){
    
    
//         cout<<"a["<<i<<"]="<<a[i].i<<'\n';
//     }
    for(int i=1;i<n;i++){
    
    
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1);
    bitset<30001>ans;
    ans[0]=1;
    for(int i=1;i<=n;i++){
    
    
        int u=a[i].i;
        int x=T[0].query(1,1,dfn[u]);
        int y=T[1].query(1,dfn[u],dfn[u]+sz[u]-1);
        ans=ans<<x | ans<<y;
        T[0].modify(1,dfn[u],1);
        T[0].modify(1,dfn[u]+sz[u],-1);
        T[1].modify(1,dfn[u],1);
    }
    int q;
    cin>>q;
    while(q--){
    
    
        int k;
        cin>>k;
        if(ans[k])cout<<"Orz"<<'\n';
        else cout<<"QAQ"<<'\n';
    }
}
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;

int n,a[N],dfn[N],sz[N],o[N],idx;
struct node{
    
    
    int tr[N];
    void add(int x,int c){
    
    
        if(x==0)return;
        for(int i=x;i<=n;i+=i&-i)tr[i]+=c;
    }
    int sum(int x){
    
    
        int ans=0;
        for(int i=x;i;i-=i&-i)ans+=tr[i];
        return ans;
    }
}T[2];
vector<int>g[N];
void dfs(int u,int fa=0){
    
    
    dfn[u]=++idx;
    sz[u]=1;
    for(auto j:g[u]){
    
    
        if(j==fa)continue;
        dfs(j,u);
        sz[u]+=sz[j];
    }
    
}
bool cmp(int &i,int &j){
    
    
    return a[i]<a[j];
}
bitset<30001>ans;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],o[i]=i;
    for(int i=1;i<n;i++){
    
    
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    ans[0]=1;
    dfs(1);
    sort(o+1,o+1+n,cmp);
    //按照权值大小排序,求每个节点有多少个祖先,多少个儿子
    for(int i=1;i<=n;i++){
    
    
        int u=o[i];
        int v1=T[0].sum(dfn[u]-1);//祖先
        int v2=T[1].sum(dfn[u]+sz[u]-1)-T[1].sum(dfn[u]-1);//儿子
        ans=ans<<v1|ans<<v2;
        T[0].add(dfn[u],1),T[0].add(dfn[u]+sz[u]-1,-1);
        T[1].add(dfn[u],1);
    }
    int q;
    cin>>q;
    while(q--){
    
    
        int x;
        cin>>x;
        if(ans[x])cout<<"Orz"<<'\n';
        else cout<<"QAQ"<<'\n';
    }
}

倍增并查集

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,p[N*21],l,r,x,y,t;
int find(int x){
    
    
    if(p[x]==x)return x;
    return p[x]=find(p[x]);
}
int get(int i,int j){
    
    
    return j*N+i;
}
void merge(int a,int b){
    
    
    p[find(a)]=find(b);
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int j=0;j<20;j++)for(int i=1;i<=n+n;i++)p[get(i,j)]=get(i,j);
    for(int i=1;i<=n;i++)merge(get(i,0),get(2*n-i+1,0));
    while(m--){
    
    
        cin>>l>>r;
        int len=r-l+1;
        int R=n*2-r+1;
        for(int j=19;j>=0;j--){
    
    
            if(len>>j&1)merge(get(l,j),get(R,j)),l+=1<<j,R+=1<<j;
        }
    }
    for(int j=19;j>=1;j--){
    
    
        for(int i=1;i<=n*2;i++){
    
    
            x=get(i,j);
            if(find(x)==x)continue;
            x=find(x);
            t=x%N;
            x=get(t,j-1);
            y=get(i,j-1);
            merge(x,y);
            x=get(t+(1<<j-1),j-1);
            y=get(i+(1<<j-1),j-1);
            merge(x,y);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
    
    
        if(find(i)==find(n-i+1))ans++;
    }
    if(ans==n)cout<<"YES"<<'\n';
    else cout<<"NO"<<'\n';
    cout<<ans;
}

天梯赛L3-2

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
const int mod=1e9+7;
int n,a[N],tr[N],r,ans,sz[N],s1,s2,s=1,f[N];
vector<int>g[N];
void add(int x,int c){
    
    
    for(int i=x;i<=n;i+=i&-i)tr[i]+=c;
}
int sum(int x){
    
    
    int ans=0;
    for(int i=x;i;i-=i&-i)ans+=tr[i];
    return ans;
}
void dfs(int u,int fa=0){
    
    
    sz[u]=1;
    add(u,1);
    s1=(s1+sum(n)-sum(u))%mod;//祖宗有多少个比我大的
    int cnt=0;
    for(auto j:g[u]){
    
    
        if(j==fa)continue;
        dfs(j,u);
        cnt++;
        sz[u]+=sz[j];
    }
    s=(s*f[cnt])%mod;//子树个数的阶乘
    add(u,-1);
    s2=(s2+n-sz[u]-sum(n))%mod;//跟我非祖宗关系的个数
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>r;
    f[0]=1;
    for(int i=1;i<=n;i++)f[i]=f[i-1]*i%mod;
    for(int i=1;i<=n;i++)a[i]=n-i+1;
    for(int i=1;i<n;i++){
    
    
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(r);
    ans=s1*s+(s2*s%mod*(mod+1)/4);
    cout<<ans%mod;
}

猜你喜欢

转载自blog.csdn.net/supreme567/article/details/127126558