csps模拟68d,e,f题解

题面:https://www.cnblogs.com/Juve/articles/11655531.html

三道数据结构?

d:

贪心,先按a排序,然后枚举删了前i个a值比较小的,然后在剩下的里面删m-i个b小的,然后统计答案

用主席树查b排名(m-i+1)或用堆维护b

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define int long long
using namespace std;
const int MAXN=1e5+5;
int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    return x;
}
int t,n,m,ans;
struct node{
    int a,b;
    friend bool operator < (node p,node q){
        return p.a<q.a;
    }
}sq[MAXN];
priority_queue<int>q;
signed main(){
    t=read();
    while(t--){
        n=read(),m=read();
        ans=0;
        for(int i=1;i<=n;++i) sq[i].a=read(),sq[i].b=read();
        sort(sq+1,sq+n+1);
        while(!q.empty()) q.pop();
        for(int i=m+1;i<=n;++i) q.push(-sq[i].b);
        for(int i=m;i>=0;--i){
            int mx=-q.top();
            ans=max(ans,mx*sq[i+1].a);
            if(sq[i].b>mx){
                q.pop();
                q.push(-sq[i].b);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN=1e5+5;
int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    return x;
}
int t,n,m,ans,mx=0;
struct node{
    int a,b;
    friend bool operator < (node p,node q){
        return p.a<q.a;
    }
}sq[MAXN];
int root[MAXN],tot=0;
struct chairman_tree{
    int ls,rs,val;
}tr[MAXN<<6];
void insert(int &now,int pre,int l,int r,int pos){
    now=++tot;tr[now]=tr[pre];++tr[now].val;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(pos<=mid) insert(tr[now].ls,tr[pre].ls,l,mid,pos);
    else insert(tr[now].rs,tr[pre].rs,mid+1,r,pos);
}
int query(int x,int y,int l,int r,int num){
    if(l==r) return l;
    int sum=tr[tr[y].ls].val-tr[tr[x].ls].val,mid=(l+r)>>1;
    if(sum>=num) return query(tr[x].ls,tr[y].ls,l,mid,num);
    else return query(tr[x].rs,tr[y].rs,mid+1,r,num-sum);
}
signed main(){
    t=read();
    while(t--){
        n=read(),m=read();
        ans=tot=mx=0;
        for(int i=1;i<=n;++i) sq[i].a=read(),sq[i].b=read(),mx=max(mx,sq[i].b);
        sort(sq+1,sq+n+1);
        for(int i=1;i<=n;++i)
            insert(root[i],root[i-1],1,mx,sq[i].b);
        for(int i=0;i<=m;++i)
            ans=max(ans,sq[i+1].a*query(root[i],root[n],1,mx,m-i+1));
        printf("%lld\n",ans);
    }
    return 0;
}
主席树

e:

开始学习主席树上树

不难看出是在每个询问点到所有询问点的lca路径上的前趋后继,然后就打的测试点分治和暴力

新知识:树上主席树,维护每个节点到根的前缀主席树,然后区间查询前趋后继

查前趋:

当前mid比val大,去右区间查找,但是会有一种情况:val等于mid+1,但主席树中没有mid+1,这时特判一下去找左区间

后继同理

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
int read(){
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
	return x;
}
const int MAXN=1e5+5;
int n,q,typ,a[MAXN],ans=0,p[MAXN],b[MAXN],mx;
int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],cnt=0;
void add(int u,int v){
	++cnt,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt;
}
int root[MAXN],tot=0;
struct node{
	int ls,rs,val;
}tr[MAXN<<6];
void insert(int &now,int pre,int l,int r,int val){
	now=++tot;tr[now]=tr[pre],++tr[now].val;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(val<=mid) insert(tr[now].ls,tr[pre].ls,l,mid,val);
	else insert(tr[now].rs,tr[pre].rs,mid+1,r,val);
}
int get_pre(int x,int y,int l,int r,int val){
	if(tr[y].val-tr[x].val==0) return 0;
	if(l==r) return l;
	int mid=(l+r)>>1,res=0;
	if(val>mid){
		res=get_pre(tr[x].rs,tr[y].rs,mid+1,r,val);
		if(res==0) res=get_pre(tr[x].ls,tr[y].ls,l,mid,val);
	}else res=get_pre(tr[x].ls,tr[y].ls,l,mid,val);
	return res;
}
int get_nxt(int x,int y,int l,int r,int val){
	if(tr[y].val-tr[x].val==0) return 0;
	if(l==r) return l;
	int mid=(l+r)>>1,res=0;
	if(val<=mid){
		res=get_nxt(tr[x].ls,tr[y].ls,l,mid,val);
		if(res==0) res=get_nxt(tr[x].rs,tr[y].rs,mid+1,r,val);
	}else res=get_nxt(tr[x].rs,tr[y].rs,mid+1,r,val);
	return res;
}
int deep[MAXN],fa[MAXN],siz[MAXN],son[MAXN];
void dfs(int x){
	siz[x]=1;
	for(int i=pre[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x]) continue;
		fa[y]=x;
		deep[y]=deep[x]+1;
		dfs(y);
		siz[x]+=siz[y];
		if(siz[son[x]]<siz[y]) son[x]=y;
	}
}
int top[MAXN];
void DFS(int x,int topf){
	insert(root[x],root[fa[x]],1,mx,a[x]);
	top[x]=topf;
	if(son[x]) DFS(son[x],topf);
	for(int i=pre[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x]||y==son[x]) continue;
		DFS(y,y);
	}
}
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(deep[x]>deep[y]) swap(x,y);
	return x;
}
signed main(){
	n=read(),q=read(),typ=read();
	for(int i=1;i<=n;++i) a[i]=read(),mx=max(mx,a[i]);
	for(int i=1,u,v;i<n;++i){
		u=read(),v=read();
		add(u,v),add(v,u);
	}
	dfs(1);DFS(1,1);
	while(q--){
		int r=read(),k=read();
		int lca;
		for(int i=1;i<=k;++i){
			p[i]=read();
			p[i]=(p[i]-1+ans*typ)%n+1;
			if(i==1) lca=p[i];
			else lca=LCA(lca,p[i]);
		}
		ans=0x3f3f3f3f;
		for(int i=1;i<=k;++i){
			int pre=get_pre(root[fa[lca]],root[p[i]],1,mx,r);
			int nxt=get_nxt(root[fa[lca]],root[p[i]],1,mx,r);
			if(pre) ans=min(ans,abs(r-pre));
			if(nxt) ans=min(ans,abs(nxt-r));
		}
		printf("%lld\n",ans);
	}
	return 0;
}

 

f:

不会了,打的暴力树状数组逆序对

posted @ 2019-10-11 17:39  xukl21  阅读(172)  评论(0编辑  收藏  举报