合适一点的题真没那么好找
文章目录
入门
T1 [USACO17JAN]Promotion Counting P
尴尬
第一,忘记空间:动态开点*20
第二,数组是从小到大拍的,也就是1小于n,而答案要统计大于p[u]
的数量
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define pb push_back
const int N=1e5+5;
int n,sz,p[N],a[N];
vector<int>G[N];
int root[N],res[N];
struct node{
int lch,rch,val;
}tre[N*20];
void discretize(){
sort(a+1,a+n+1);
int lim=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;++i)
p[i]=lower_bound(a+1,a+lim+1,p[i])-a;
return;
}
void push_up(int p){
if(!tre[p].lch&&!tre[p].rch) return;
tre[p].val=tre[tre[p].lch].val+tre[tre[p].rch].val;
return;
}
void update(int &p,int l,int r,int pos,int v){
if(!p) p=++sz;
if(l==r){
tre[p].val+=v;
return;
}
int mid=l+r>>1;
if(pos<=mid) update(tre[p].lch,l,mid,pos,v);
else update(tre[p].rch,mid+1,r,pos,v);
push_up(p);
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
tre[p].val+=tre[rt].val;
return p;
}
int mid=l+r>>1;
tre[p].lch=merge(tre[p].lch,tre[rt].lch,l,mid);
tre[p].rch=merge(tre[p].rch,tre[rt].rch,mid+1,r);
push_up(p);
return p;
}
int query(int p,int l,int r,int L,int R){
if(!p) return 0;
if(L<=l&&r<=R) return tre[p].val;
int mid=l+r>>1,ans=0;
if(L<=mid) ans+=query(tre[p].lch,l,mid,L,R);
if(R>mid) ans+=query(tre[p].rch,mid+1,r,L,R);
return ans;
}
void work(int u,int fa){
for(int v:G[u]) if(v^fa){
work(v,u);
root[u]=merge(root[u],root[v],1,n);
}
res[u]=query(root[u],1,n,p[u]+1,n);
return;
}
int main(){
n=in;
for(int i=1;i<=n;++i) p[i]=a[i]=in;
discretize();
for(int u=2;u<=n;++u){
int v=in;
G[u].pb(v);
G[v].pb(u);
}
for(int i=1;i<=n;++i)
update(root[i],1,n,p[i],1);
work(1,0);
for(int i=1;i<=n;++i)
printf("%d\n",res[i]);
// for(int i=1;i<=n;++i) printf("%d ",p[i]);
return 0;
}
T2 Lomsat gelral
启发式合并其实就是一种思想,小的并到大的去(有点暴力)
总之
O
(
n
log
n
)
O(n\log n)
O(nlogn)
线段树合并注意处理编号频数相等的情况
果然又是long long的锅
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define lch tre[p].lc
#define rch tre[p].rc
const int N=1e5+5;
int n,col[N],sz;
vector<int>G[N];
int res[N],lim;
int root[N];
struct Tree{
int lc,rc,max,ans,cnt;
}tre[N*20];
void push_up(int p){
if(!lch&&!rch) return;
if(tre[lch].cnt>tre[rch].cnt){
tre[p].cnt=tre[lch].cnt;
tre[p].max=tre[lch].max;
tre[p].ans=tre[lch].ans;
}else if(tre[lch].cnt<tre[rch].cnt){
tre[p].cnt=tre[rch].cnt;
tre[p].max=tre[rch].max;
tre[p].ans=tre[rch].ans;
}else{
tre[p].cnt=tre[lch].cnt;
tre[p].max=tre[lch].max;
tre[p].ans=tre[lch].ans+tre[rch].ans;
}
}
void update(int &p,int l,int r,int pos,int v){
if(!p) p=++sz;
if(l==r){
tre[p].cnt+=v;
tre[p].max=l;
tre[p].ans=l;
return;
}
int mid=l+r>>1;
if(pos<=mid) update(lch,l,mid,pos,v);
else update(rch,mid+1,r,pos,v);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
tre[p].cnt+=tre[rt].cnt;
tre[p].max=l;
tre[p].ans=l;
return p;
}
int mid=l+r>>1;
lch=merge(lch,tre[rt].lc,l,mid);
rch=merge(rch,tre[rt].rc,mid+1,r);
push_up(p);
return p;
}
void DFS(int u,int fa){
// printf("%d %d\n",u,fa);
for(int v:G[u]) if(v^fa){
DFS(v,u);
root[u]=merge(root[u],root[v],1,lim);
}
update(root[u],1,lim,col[u],1);
res[u]=tre[root[u]].ans;
return;
}
signed main(){
n=in;
for(int i=1;i<=n;++i) lim=max(lim,col[i]=in);
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].push_back(v);
G[v].push_back(u);
}
DFS(1,0);
for(int i=1;i<=n;++i)
printf("%lld ",res[i]);
return 0;
}
T3 [POI2011]ROT-Tree Rotations
考虑逆序对的出处:
- 左儿子
- 右儿子
- 跨越左右儿子
显然我们能减小的是第三种
利用权值线段树,每次合并对答案的贡献为是否交换逆序对的最小值
合并时push_up
贡献:
- 不交换,A树左儿子大小*B树右儿子大小
- 要交换,B树左儿子大小*A树右儿子大小
注意合并时先加权值再往下递推
要保证上述子树大小是原汁原味的子树大小,不能是经过合并被像面团一样挼在一起的子树大小
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
const int N=8e5+5,M=N*20;
int n,sz,lch[M],rch[M],val[M],ans,ans1,ans2;
int tot,lsn[N],rsn[N],ran[N],Root,root[N];
void DFS(int &rt){
if(!rt) rt=++tot;
ran[rt]=in;
if(ran[rt]) return;
DFS(lsn[rt]);
DFS(rsn[rt]);
return;
}
void push_up(int p){val[p]+=val[lch[p]]+val[rch[p]];}
void update(int &p,int l,int r,int pos,int v){
if(!p) p=++sz;
if(l==r){
val[p]+=v;
return;
}
int mid=l+r>>1;
if(pos<=mid) update(lch[p],l,mid,pos,v);
else update(rch[p],mid+1,r,pos,v);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
val[p]+=val[rt];
return p;
}
val[p]+=val[rt];
ans1+=val[lch[p]]*val[rch[rt]];
ans2+=val[lch[rt]]*val[rch[p]];
int mid=l+r>>1;
lch[p]=merge(lch[p],lch[rt],l,mid);
rch[p]=merge(rch[p],rch[rt],mid+1,r);
return p;
}
void work(int rt){
if(!ran[rt]){
work(lsn[rt]);
work(rsn[rt]);
ans1=ans2=0;
root[rt]=merge(root[lsn[rt]],root[rsn[rt]],1,n);
ans+=min(ans1,ans2);
}else update(root[rt],1,n,ran[rt],1);
return;
}
signed main(){
n=in;
DFS(Root);
work(Root);
printf("%lld\n",ans);
return 0;
}
T4 Dominant Indices
某位大佬
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
const int N=1e6+5,M=N*25;
int n,sz,lch[M],rch[M],deg[M],ans[N];
int root[N],dep[N],son[M];
vector<int>G[N];
void push_up(int p){
if(son[lch[p]]>=son[rch[p]]){
son[p]=son[lch[p]];
deg[p]=deg[lch[p]];
}else{
son[p]=son[rch[p]];
deg[p]=deg[rch[p]];
}
return;
}
void update(int &p,int l,int r,int pos,int v){
if(!p) p=++sz;
if(l==r){
deg[p]=l;
son[p]+=v;
return;
}
int mid=l+r>>1;
if(pos<=mid) update(lch[p],l,mid,pos,v);
else update(rch[p],mid+1,r,pos,v);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
son[p]+=son[rt];
return p;
}
int mid=l+r>>1;
lch[p]=merge(lch[p],lch[rt],l,mid);
rch[p]=merge(rch[p],rch[rt],mid+1,r);
push_up(p);
return p;
}
void DFS(int u,int fa){
dep[u]=dep[fa]+1;
update(root[u],1,n,dep[u],1);
for(int v:G[u]) if(v^fa){
DFS(v,u);
root[u]=merge(root[u],root[v],1,n);
}
ans[u]=deg[root[u]]-dep[u];
return;
}
int main(){
n=in;
for(int i=1;i<n;++i){
int u=in,v=in;
G[u].push_back(v);
G[v].push_back(u);
}
DFS(1,0);
for(int i=1;i<=n;++i)
printf("%d\n",ans[i]);
return 0;
}
T5 [HNOI2012]永无乡
Portkey
名字好有诗意啊
并查集维护连通性
合并权值线段树查第K大
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define pb push_back
const int N=5e5+5,M=N*25;
int n,m,q,rnk[N],fa[N],root[N];
int sz,lch[M],rch[M],num[M],idx[M];
char ch[5];
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
void push_up(int p){num[p]=num[lch[p]]+num[rch[p]];}
void print_tree(int p){
printf("%d %d %d %d\n",p,num[p],lch[p],rch[p]);
if(lch[p]) print_tree(lch[p]);
if(rch[p]) print_tree(rch[p]);
}
void update(int &p,int l,int r,int pnt,int v){
if(!p) p=++sz;
if(l==r){
num[p]++;
idx[p]=v;
return;
}
int mid=l+r>>1;
if(pnt<=mid) update(lch[p],l,mid,pnt,v);
else update(rch[p],mid+1,r,pnt,v);
push_up(p);
return;
}
int merge(int p,int rt,int l,int r){
if(!p||!rt) return p|rt;
if(l==r){
if(idx[rt]){
idx[p]=idx[rt];
num[p]+=num[rt];
}
return p;
}
int mid=l+r>>1;
lch[p]=merge(lch[p],lch[rt],l,mid);
rch[p]=merge(rch[p],rch[rt],mid+1,r);
push_up(p);
return p;
}
int query(int p,int l,int r,int k){
if(k>num[p]||!p) return 0;
if(l==r) return idx[p];
int mid=l+r>>1;
if(k<=num[lch[p]]) return query(lch[p],l,mid,k);
else return query(rch[p],mid+1,r,k-num[lch[p]]);
}
int main(){
n=in,m=in;
for(int i=1;i<=n;++i){
rnk[i]=in;
fa[i]=i;
update(root[i],1,n,rnk[i],i);
}
for(int i=1;i<=m;++i){
int u=get(in),v=get(in);
fa[v]=u;
root[u]=merge(root[u],root[v],1,n);
}
q=in;
for(int i=1;i<=q;++i){
scanf("%s",ch);
if(ch[0]=='Q'){
int u=get(in),k=in,ans;
ans=query(root[u],1,n,k);
if(!ans) puts("-1");
else printf("%d\n",ans);
}else{
int u=in,v=in;
u=get(u),v=get(v);
if(u==v) continue;
fa[v]=u;
root[u]=merge(root[u],root[v],1,n);
}
}
return 0;
}