文章目录
高级数据结构:
并查集:
ps:f表示父亲,d表示路径长度
查找(带权):
int Get(int now)
{
if (now == f[now]) return now;
int fa = Get(f[now]);
d[now] += d[f[now]];
return f[now] = fa;
}
合并(权值要以具体题目来讲所以略):
int fa=Get(x);
int fb=Get(y);
f[fa]=fb;
扩展域
由于传递的关系复杂,然后就扩充??(如食物链,有同类天敌捕食)
树状数组
单点修改区间查询
ps:此处修改值加上某个值,查询为前缀和
void Add(int now,int v)
{
for (;now<=n;now+=now&(-now)) c[now]+=v;
}
long long find(int now)
{
long long ans=0;
for (;now;now-=now&(-now)) ans+=c[now];
return ans;
}
区间修改单点查询
ps:修改:加上某个数;查询:某个数的值
差分一下,就比上面多个差分
区间修改区间查询
void Add(int now,long long v)
{
int x=now;
for (;now<=n;now+=now&(-now))
c[now]+=v,cc[now]+=x*v;
}
long long find(int now)
{
int x=now+1;
long long ans=0;
for (;now;now-=now&(-now))
ans+=x*c[now],ans-=cc[now];
return ans;
}
int main()//极端简化
{
Add(x,v);
Add(y+1,-v);
printf("%lld\n",find(y)-find(x-1));
}
二维树状数组
void Add(int x,int y,int v)
{
for (;x<=n;x+=x&(-x))
{
int yy=y;
for (;yy<=n;yy+=yy&(-yy))
c[x][yy]+=v;
}
return ;
}
int find(int x,int y)
{
int ans=0;
for (;x;x-=x&(-x))
{
int yy=y;
for (;yy;yy-=yy&(-yy))
ans+=c[x][yy];
}
return ans;
}
线段树:
模板
void build(int now,int ll,int rr)//建树
{
t[now].l=ll;t[now].r=rr;
if (ll==rr) return ;
int mid=(ll+rr)/2;
build(now*2,ll,mid);
build(now*2+1,mid+1,rr);
}
void pass(int now)//传递标记
{
t[now*2].Max+=t[now].del;
t[now*2].del+=t[now].del;
t[now*2+1].Max+=t[now].del;
t[now*2+1].del+=t[now].del;
t[now].del=0;
}
void change(int now,int ll,int rr)//区修
{
if (ll==t[now].l&&rr==t[now].r)
{
t[now].Max++;
t[now].del++;
return ;
}
pass(now);
int mid=(t[now].l+t[now].r)/2;
if (rr<=mid) change(now*2,ll,rr);
else if (ll>mid) change(now*2+1,ll,rr);
else change(now*2,ll,mid),change(now*2+1,mid+1,rr);
t[now].Max=max(t[now*2].Max,t[now*2+1].Max);
}
int find(int now,int ll,int rr)//区间查询
{
if (ll==t[now].l&&rr==t[now].r)
return t[now].Max;
pass(now);
int mid=(t[now].l+t[now].r)/2;
if (rr<=mid) return find(now*2,ll,rr);
else if (ll>mid) return find(now*2+1,ll,rr);
else return max(find(now*2,ll,mid),find(now*2+1,mid+1,rr));
}
动态开点+线段树合并
int build()//建点
{
tot++;
t[tot].l=t[tot].r=t[tot].sum=0;
return tot;
}
int merge(int p,int q,int l,int r)//合并
{
if (!p) return q;
if (!q) return p;
if (l==r)
{
t[p].sum+=t[q].sum;
return p;
}
int mid=(l+r)/2;
t[p].l=merge(t[p].l,t[q].l,l,mid);
t[p].r=merge(t[p].r,t[q].r,mid+1,r);
t[p].sum=t[t[p].l].sum+t[t[p].r].sum;
return p;
}
int find(int p,int ll,int rr,int l,int r)//区间查询
{
if (!p) return 0;
if (l==ll&&r==rr) return t[p].sum;
int mid=(l+r)/2;
if (rr<=mid)
return find(t[p].l,ll,rr,l,mid);
if (ll>mid)
return find(t[p].r,ll,rr,mid+1,r);
return find(t[p].l,ll,mid,l,mid)+find(t[p].r,mid+1,rr,mid+1,r);
}
void change(int p,int x,int l,int r)//这是个单点修改
{
if (l==x&&r==x)
{
t[p].sum++;
return ;
}
int mid=(l+r)/2;
if (x<=mid)
{
if (!t[p].l) t[p].l=build();
change(t[p].l,x,l,mid);
}
else
{
if (!t[p].r) t[p].r=build();
change(t[p].r,x,mid+1,r);
}
t[p].sum=t[t[p].l].sum+t[t[p].r].sum;
return ;
}
扫描线
这是个啥,我不知道o((⊙﹏⊙))o
#include <bits/stdc++.h>
using namespace std;
int n,tot=0;
long long W,H,b[200010];
struct dsa
{
long long x,y,Y,v;
}a[200010];
struct das
{
int l,r;
long long Max,dat;
}t[800010];
inline bool cmp(dsa p,dsa q)
{
return p.x<q.x||(p.x==q.x&&p.v>q.v);
}
inline int find(long long now)
{
int l=1,r=tot;
while (l+1<r)
{
int mid=(l+r)>>1;
if (b[mid]<now) l=mid+1;else r=mid;
}
if (b[l]==now) return l;else return r;
}
inline void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;t[p].Max=0;t[p].dat=0;
if (l==r) return ;
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
return ;
}
inline void pass(int p)
{
t[p*2].Max+=t[p].dat;
t[p*2].dat+=t[p].dat;
t[p*2+1].dat+=t[p].dat;
t[p*2+1].Max+=t[p].dat;
t[p].dat=0;
return ;
}
inline void change(int p,int l,int r,long long v)
{
if (t[p].l==l&&t[p].r==r)
{
t[p].dat+=v;
t[p].Max+=v;
return ;
}
pass(p);
int mid=(t[p].l+t[p].r)>>1;
if (r<=mid) change(p*2,l,r,v);
else if (l>mid) change(p*2+1,l,r,v);
else change(p*2,l,mid,v),change(p*2+1,mid+1,r,v);
t[p].Max=max(t[p*2].Max,t[p*2+1].Max);
return ;
}
int main()
{
freopen("stars.in","r",stdin);
freopen("stars.out","w",stdout);
while (~scanf("%d%lld%lld",&n,&W,&H))
{
long long ans=0;
W--;H--;
for (int i=1;i<=n;i++)
{
long long x,y,c;
scanf("%lld%lld%lld",&x,&y,&c);
a[i].x=x;a[i].y=y;a[i].Y=y+H;a[i].v=c;
a[i+n].x=x+W;a[i+n].y=y;a[i+n].Y=y+H;a[i+n].v=-c;
b[i]=y;b[i+n]=y+H;
}
sort(b+1,b+2*n+1);
tot=0;
for (int i=1;i<=2*n;i++)
if (b[tot]!=b[i]||!tot) b[++tot]=b[i];
build(1,1,tot);
sort(a+1,a+2*n+1,cmp);
for (int i=1;i<=2*n;i++)
{
change(1,find(a[i].y),find(a[i].Y),a[i].v);
ans=max(t[1].Max,ans);
}
printf("%lld\n",ans);
}
return 0;
}
分块
#include <bits/stdc++.h>
using namespace std;
int n,a[50010],b[50010],blo[50010];
int size;
void Add(int l,int r,int c)
{
for (int i=l;i<=min(blo[l]*size,r);i++)
a[i]+=c;
if (blo[l]!=blo[r])
for (int i=(blo[r]-1)*size+1;i<=r;i++)
a[i]+=c;
for (int i=blo[l]+1;i<blo[r];i++)
b[i]+=c;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
size=sqrt(n*1.0);
for (int i=1;i<=n;i++)
blo[i]=(i-1)/size+1;
for (int i=1;i<=n;i++)
{
int type,l,r,c;
scanf("%d%d%d%d",&type,&l,&r,&c);
if (type==0)
Add(l,r,c);
else printf("%d\n",a[r]+b[blo[r]]);
}
return 0;
}
莫队
考虑扩展
#include <bits/stdc++.h>
using namespace std;
int n,m,k;
int v[5000010],a[100010],s[100010];
long long sum=0,ans[100010];
int size;
struct dsa
{
int l,r,id;
}qu[100010];
bool cmp(dsa p,dsa q)
{
if ( ( p.l/size ) != ( q.l/size ) )
return p.l/size<q.l/size;
if ((p.l/size)&1)
return p.r<q.r;
else return p.r>q.r;
}
void insert_(int x)
{
sum+=v[s[x]^k];
v[s[x]]++;
}
void delete_(int x)
{
v[s[x]]--;
sum-=v[s[x]^k];
}
int main()
{
freopen("2011.in","r",stdin);
freopen("2011.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),s[i]=s[i-1]^a[i];
for (int i=1;i<=m;i++)
scanf("%d%d",&qu[i].l,&qu[i].r),qu[i].id=i;
size=n*1.0/sqrt(n*1.0);
sort(qu+1,qu+m+1,cmp);
int ll=1,rr=1;
insert_(1);
for (int i=1;i<=m;i++)
{
qu[i].l--;
while (ll>qu[i].l) insert_(--ll);
while (ll<qu[i].l) delete_(ll++);
while (rr<qu[i].r) insert_(++rr);
while (rr>qu[i].r) delete_(rr--);
ans[qu[i].id]=sum;
}
for (int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
点分治
考虑过根的贡献
#include <bits/stdc++.h>
using namespace std;
int n,k,sum[10010],root,d[10010],b[10010],Link[10010],s,Min;
int a[10010],tot,cnt[10010],ans=0,t;
bool vis[10010];
struct dsa
{
int v,nex,w;
}e[20010];
void insert(int xx,int yy,int zz)
{
e[++t].nex=Link[xx];
e[t].v=yy;
e[t].w=zz;
Link[xx]=t;
}
bool cmp(int p1,int p2)
{
return d[p1]<d[p2];
}
void get_root(int now,int fa)
{
sum[now]=1;
int Max=0;
for (int i=Link[now];i;i=e[i].nex)
{
if (e[i].v==fa||vis[e[i].v]) continue;
get_root(e[i].v,now);
Max=max(Max,sum[e[i].v]);
sum[now]+=sum[e[i].v];
}
Max=max(Max,s-sum[now]);
if (Max<Min) Min=Max,root=now;
}
void get_dis(int now,int fa,int ty)
{
b[now]=ty;
a[++tot]=now;
for (int i=Link[now];i;i=e[i].nex)
{
if (e[i].v==fa||vis[e[i].v]) continue;
d[e[i].v]=d[now]+e[i].w;
get_dis(e[i].v,now,ty);
}
return;
}
void work(int now)
{
for (int i=1;i<=n;i++)
cnt[i]=0;
b[now]=now;
d[now]=0;
tot=0;
a[++tot]=now;
for (int i=Link[now];i;i=e[i].nex)
{
if (vis[e[i].v]) continue;
d[e[i].v]=e[i].w;
get_dis(e[i].v,now,e[i].v);
}
sort(a+1,a+tot+1,cmp);
int l=1,r=tot;
for (int i=2;i<=tot;i++)
cnt[b[a[i]]]++;
while (l<r)
if (d[a[l]]+d[a[r]]<=k)
{
ans+=r-l-cnt[b[a[l]]];
l++;
cnt[b[a[l]]]--;
}
else cnt[b[a[r]]]--,r--;
}
void solve(int now,int fa)
{
work(now);
vis[now]=true;
for (int i=Link[now];i;i=e[i].nex)
{
if (e[i].v==fa||vis[e[i].v]) continue;
Min=1e9;root=0;
s=sum[e[i].v];
get_root(e[i].v,0);
solve(root,0);
}
}
int main()
{
freopen("poj1741_tree.in","r",stdin);
freopen("poj1741_tree.out","w",stdout);
scanf("%d%d",&n,&k);
while (n||k)
{
t=0;
memset(Link,0,sizeof(Link));
memset(vis,0,sizeof(vis));
ans=0;
for (int i=1;i<n;i++)
{
int xx,yy,zz;
scanf("%d%d%d",&xx,&yy,&zz);
insert(xx,yy,zz);
insert(yy,xx,zz);
}
s=n;
Min=1e9;
root=0;
get_root(1,0);
solve(root,0);
printf("%d\n",ans);
scanf("%d%d",&n,&k);
}
return 0;
}
可持久化
可持久化trie
#include <bits/stdc++.h>
using namespace std;
int n,m,cnt=0,root[600010],la[14000010],t[14000010][2],s[600010];
int ans=0;
void Insert(int p,int q,int val,int now,int num)
{
if (now < 0)
{
la[q]=num;
return ;
}
int x=(val >> now) & 1;
if (p) t[q][x^1] = t[p][x^1];
t[q][x] = ++cnt;
Insert(t[p][x],t[q][x],val,now - 1,num);
la[q] = max(la[t[q][0]],la[t[q][1]]);
}
void Find(int p,int val,int now,int l)
{
if (now < 0) return ;
int c = (val >> now) & 1;
if (t[p][c ^ 1] && la[t[p][c ^ 1]] >= l)
ans += (1 << now),Find(t[p][c ^ 1],val,now - 1,l);
else if (la[t[p][c]] >= l) Find(t[p][c],val,now - 1,l);
return ;
}
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
scanf("%d%d",&n,&m);
s[0]=0;
root[0]=++cnt;
Insert(0,root[0],0,24,0);
for (int i = 1;i <= n;i++)
{
int x;
scanf("%d",&x);
s[i] = s[i - 1] ^ x;
root[i] = ++cnt;
Insert(root[i - 1],root[i],s[i],24,i);
}
for (int i = 1;i <= m;i++)
{
char ch[5];
int x,l,r;
scanf("%s",ch);
if (ch[0]=='A')
{
scanf("%d",&x);
n++;
root[n]=++cnt;
s[n]=s[n - 1]^x;
Insert(root[n - 1],root[n],s[n],24,n);
}
else
{
scanf("%d%d%d",&l,&r,&x);
ans=0;
Find(root[r - 1],s[n]^x,24,l - 1);
printf("%d\n",ans);
}
}
return 0;
}
主席树
#include <bits/stdc++.h>
using namespace std;
int n,m,root[100010],cnt=0,b[100010],num=0,a[100010];
struct dsa
{
int sum,l,r;
}t[2000010];
int Get(int now)
{
int l = 1,r = num;
while (l + 1 < r)
{
int mid = (l + r) >> 1;
if (now > b[mid]) l = mid + 1;
else r = mid;
}
if (b[l] == now) return l;else return r;
}
void build(int p,int &q,int l,int r,int x)
{
q = ++cnt;
t[q].l = t[p].l;
t[q].r = t[p].r;
t[q].sum = t[p].sum+1;
if (l == r) return;
int mid = (l + r) >> 1;
if (x <= mid) build(t[p].l,t[q].l,l,mid,x);
else build(t[p].r,t[q].r,mid+1,r,x);
}
int Find(int p,int q,int l,int r,int x)
{
if (l == r) return l;
int mid = (l + r )>> 1;
int s = t[t[q].l].sum - t[t[p].l].sum;
if (x <= s) return Find(t[p].l,t[q].l,l,mid,x);
else return Find(t[p].r,t[q].r,mid + 1,r,x - s);
}
int main()
{
freopen("kth.in","r",stdin);
freopen("kth.out","w",stdout);
scanf("%d%d",&n,&m);
root[0] = 0;
for (int i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(b + 1,b + n + 1);num = 0;
for (int i = 1;i <= n;i++)
if (!num || b[num] != b[i]) b[++num] = b[i];
for (int i = 1;i <= n;i++)
{
build (root[i - 1],root[i],1,num,Get(a[i]));
}
for (int i = 1;i <= m;i++)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",b[Find(root[l-1],root[r],1,num,x)]);
}
return 0;
}
可持久化线段树
#include <bits/stdc++.h>
using namespace std;
int n,m,root[100010],a[10010],cnt=0;
struct dsa
{
int l,r,Max;
}t[2010010];
void Pre(int &p,int l,int r)
{
p=++cnt;
if (l==r) {t[p].Max=a[l];return ;}
int mid=(l+r)>>1;
Pre(t[p].l,l,mid);
Pre(t[p].r,mid+1,r);
t[p].Max=max(t[t[p].l].Max,t[t[p].r].Max);
}
int Find(int p,int l,int r,int ll,int rr)
{
if (!p) return 0;
if (l==ll&&r==rr) return t[p].Max;
int mid=(l+r)>>1;
if (rr<=mid) return Find(t[p].l,l,mid,ll,rr);
if (ll>mid) return Find(t[p].r,mid+1,r,ll,rr);
return max(Find(t[p].l,l,mid,ll,mid),Find(t[p].r,mid+1,r,mid+1,rr));
}
void build(int p,int &q,int l,int r,int x,int val)
{
q=++cnt;
t[q].l=t[p].l;
t[q].r=t[p].r;
if (l==r)
{
t[q].Max=val;
return ;
}
int mid=(l+r)>>1;
if (x<=mid) build(t[p].l,t[q].l,l,mid,x,val);
else build(t[p].r,t[q].r,mid+1,r,x,val);
t[q].Max=max(t[t[q].l].Max,t[t[q].r].Max);
}
int main()
{
freopen("longterm_segtree.in","r",stdin);
freopen("longterm_segtree.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
root[1]=0;
Pre(root[1],1,n);
int s=1;
for (int i=1;i<=m;i++)
{
int type,l,r,k,x;
scanf("%d%d%d%d",&type,&k,&l,&r);
if (type==0)
printf("%d\n",Find(root[k],1,n,l,r));
else build(root[k],root[++s],1,n,l,r);
}
return 0;
}