题面: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 ",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 ",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 ",ans); } return 0; }
f:
不会了,打的暴力树状数组逆序对