2024.8.20 DS训练

A - Monkey King

可以可并堆,但是我蔡

考虑DSU+启发式合并,发现做完了

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int fa[N];
priority_queue<int> q[N];
int n,m;
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}

void merge(int x,int y){
    fa[x]=y;
    while(!q[x].empty()){
        q[y].push(q[x].top());
        q[x].pop();
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    while(cin>>n){
        for(int i=1,in;i<=n;i++){
            cin>>in;
            fa[i]=i;   
            while(!q[i].empty()) q[i].pop();
            q[i].push(in);
        }
        cin>>m;
        for(int i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            x=find(x),y=find(y);
            if(x==y){
                cout<<"-1\n";
                continue;
            }
            if(q[x].size()>q[y].size()) swap(x,y);
            int X=q[x].top()/2,Y=q[y].top()/2;
            q[x].pop(),q[y].pop();
            merge(x,y);
            q[y].push(X),q[y].push(Y);
            cout<<q[y].top()<<"\n";
        }
    }
}

B - KUR-Couriers

考虑直接求区间众数

搞了个分块发现没过,原因在于分块空间和时间都很劣,常数大

整个莫队

#include<bits/stdc++.h> 
using namespace std;
const int N=5e5+5,BL=715;
int n, m;
int a[N];
struct QU {
    int l,r,id;
} q[N];
int ans[N];
int len,num,K[N];
int cnt[N];
int L[N],R[N];

bool cmp(QU x,QU y){ 
    return K[x.l]!=K[y.l]?K[x.l]<K[y.l]:x.r<y.r;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=m;i++){
        cin>>q[i].l>>q[i].r;
        q[i].id = i;
    }
    len=sqrt(n);
    num=n/len;
    for(int i=1;i<=num;i++){
        L[i]=(i-1)*len+1;
        R[i]=i*len;
    }
    if(R[num]!=n){
        L[num+1]=R[num]+1;
        R[++num]=n;
    }
    for(int i=1;i<=num;i++) fill(K+L[i],K+R[i]+1,i);
    sort(q+1,q+m+1,cmp);
    int l=1,r=0,lst=0,mx,fr;
    for(int i=1;i<=m;i++){
        if(K[q[i].l]!=lst) {
            while(r>=l) cnt[a[r--]]--;
            mx=0;fr=0;
            lst=K[q[i].l];
            r=R[lst];
            l=r+1;
        }
        if(K[q[i].l]==K[q[i].r]) {
            for(int j=q[i].l;j<=q[i].r;j++)
                if(++cnt[a[j]]>mx)
                    mx=cnt[fr=a[j]];
            ans[q[i].id]=mx*2>(q[i].r-q[i].l+1)?fr:0;
            for(int j=q[i].l;j<=q[i].r;j++)--cnt[a[j]];
            mx=fr=0;
            continue;
        }
        while(r<q[i].r) {
            if(++cnt[a[++r]]>mx)
                mx=cnt[fr=a[r]];
        }
        int lol=l,tmp=mx,ffr=fr;
        while(lol>q[i].l) {
            if(++cnt[a[--lol]]>tmp)
                tmp=cnt[ffr=a[lol]];
        }
        ans[q[i].id]=tmp*2>(q[i].r-q[i].l+1)?ffr:0;
        while(lol<l) --cnt[a[lol++]];
    }
    for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
    return 0;
}

C - 不等式组

不妨考虑树状数组,把不等式转化为三类:

恒成立,恒不成立,大于号,小于号

前两种直接记录,后两种上树状数组维护

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int n,C[N],c[N],top,kd[N],k[N],cnt;
char s[20];
bool D[N];
void add(int x,int k,int t[]){
    x+=1e6+1;
    for(;x<N;x+=x&-x){
        t[x]+=k;
    }
}
int sum(int x,int t[],int res=0){
	x+=1e6+1;
	for(;x;x-=x&(-x))
		res+=t[x];
	return res;
}

int main(){
    cin>>n;
    int x,y,z;
    while(n--){
        cin>>s;
        if(s[0]=='A'){
            cin>>x>>y>>z;
            if(!x){
                if(y>z){
                    cnt++;
                    kd[++top]=3;
                }
                else kd[++top]=0;
            }
            if(x>0){
                k[++top]=floor((z*1.0-y)/x);
                kd[top]=1;
                if(k[top]>1e6) kd[top]=0;
				else if(k[top]<-1e6){
					cnt++;
					kd[top]=3;
				}
                else{
                    add(k[top],1,C);
                }
            }
            if(x<0){
                k[++top]=ceil((z*1.0-y)/x);
                kd[top]=2;
                if(k[top]<-1e6) kd[top]=0;
				else if(k[top]>1e6){
					cnt++; 
					kd[top]=3;
				}
                else{
                    add(k[top],1,c);
                }
            }
        }
        else if(s[0]=='Q'){
            cin>>x;
			cout<<sum(x-1,C)+sum(1e6,c)-sum(x,c)+cnt<<"\n";
        }
        else{
            cin>>x;
			if(D[x]) continue ;
			D[x]=true;
			if(kd[x] == 3) cnt--;
			if(kd[x] == 1) add(k[x],-1,C);
			if(kd[x] == 2) add(k[x],-1,c);
		}
    }
}

H - Tree Requests

考虑dsu on tree

把询问挂到每个点上

暴力好想,只要出现奇数次的字母数量不超过一即可

套上链分治就做完了的说

#include<bits/stdc++.h>
using namespace std;
#define ei for(int i=hd[x],v;i;i=e[i].nxt)
const int N=1000005;
int n,m;
bool vis[N];
struct edge{
    int v,nxt;
}e[N];
int hd[N],cnt;
void add(int u,int v){
    e[++cnt]={v,hd[u]},hd[u]=cnt;
    e[++cnt]={u,hd[v]},hd[v]=cnt;
} 
int sz[N],sum[N],son[N],dep[N],ans[N],tot[N][26];

struct node{
    int k,id;
};
vector<node> Q[N];
char s[N];

void dfs(int x,int fa){
    sz[x]=1;
    dep[x]=dep[fa]+1;
    ei{
        if((v=e[i].v)==fa) continue;
        dfs(v,x);
        sz[x]+=sz[v];
        if(sz[v]>sz[son[x]]) son[x]=v;
    }
}
void calc(int x,int fa,int val){
	tot[dep[x]][s[x]-'a']+=val;
    ei{
		if((v=e[i].v)==fa or vis[v]) continue;
		calc(v,x,val);
	}
}
bool check(int s[]){
	int r=0;
	for(int i=0;i<26;++i){
		if(s[i]&1) ++r;
		if(r>1) return 0;
	}
	if(r>1) return 0;
	return 1;
}
void dfs2(int x,int fa,int keep){
    ei{
		if((v=e[i].v)==fa or v==son[x]) continue;
		dfs2(v,x,0);
	}
	if(son[x]) dfs2(son[x],x,1),vis[son[x]]=1;
	calc(x,fa,1),vis[son[x]]=0;
	for(int i=0;i<Q[x].size();++i) ans[Q[x][i].id]=check(tot[Q[x][i].k]);
	if(!keep) calc(x,fa,-1);
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=2,u;i<=n;++i){
        cin>>u;
		add(u,i);
	}
    cin>>s+1;
    dfs(1,0);
    for(int i=1,a,b;i<=m;++i){
		cin>>a>>b;
		Q[a].push_back((node){b,i});
	}
	dfs2(1,0,0);
	for(int i=1;i<=m;++i)
		cout<<(ans[i]?"Yes\n":"No\n");
}
posted @ 2024-08-20 08:43  exut  阅读(7)  评论(0编辑  收藏  举报
Title