数据结构复习(模板)

高级数据结构:

并查集:

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;
}
		

猜你喜欢

转载自blog.csdn.net/yu25_21_5/article/details/90672416
今日推荐