• 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流


    【BZOJ3681】Arietta

    Description

    Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中。
    但是她从未停止过和恋人 Velding 的书信往来。一天,她准备去探访他。
    对着窗外的阳光,临行前她再次弹起了琴。
    她的琴的发声十分特殊。
    让我们给一个形式化的定义吧。
    所有的 n 个音符形成一棵由音符 C ( 1 号节点) 构成的有根树,每一个音符有一个音高 Hi 。
    Arietta 有 m 个力度,第 i 个力度能弹出 Di 节点的子树中,音高在 [Li,Ri] 中的任意一个音符。
    为了乐曲的和谐,Arietta 最多会弹奏第 i 个力度 Ti 次。
    Arietta 想知道她最多能弹出多少个音符。

    Input

    输入共 m + 3 行。
    第一行两个整数 n, m ,意义如题目所述。
    第二行 n - 1 个整数 Pi ,表示节点 i ( i = 2 . . . n ) 的父亲节点的编号。
    第三行 n 个整数 Hi 。
    接下来的 m 行,每行四个整数 Li,Ri,D,Ti

    Output

    输出一个整数表示 Arietta 最多能弹奏多少音符。
    数据范围与约定
    对于 100% 的数据,1 ≤ n, m ≤ 10000 。
    对于所有数据,1 ≤ Hi , Ti , Pi ≤ n, 1 ≤ Li ≤ Ri ≤ n 。

    Sample Input

    5 2
    1 1 2 2
    5 3 2 4 1
    1 3 2 1
    3 5 1 4

    Sample Output

    4

    HINT

    第一个力度弹奏音符5,第二个力度弹奏音符1,2,4。

    数据范围与约定
    对于 100% 的数据,1 ≤ n, m ≤ 10000 。
    对于所有数据1<=Hi,Ti,Pi<=N,1<=Li<=Ri<=N

    题解:树剖还真是神通广大啊~

    容易想到用最大流解决,但是边数太大,考虑用线段树优化建图的过程。我们对于每个节点都维护一棵线段树,维护它子树中所有点的音高。然后我们将x的所有儿子的线段树与x合并到一起就得到了x的线段树(然而线段树合并是不资瓷的。)

    暴力合并显然边数还是爆炸,但是我们可以对原树进行轻重链剖分,将线段树变成可持久化线段树。对于将x的重儿子与x合并这个过程,直接通过可持久化解决,其余的儿子暴力插入,这样边数就变成$O(nlog^2_n)$的了。

    最后在可持久化线段树上连边即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    const int maxn=10010;
    int n,m,tot,cnt,S,T,ans;
    int fa[maxn],to[maxn*240],next[maxn*240],val[maxn*240],head[maxn*80],d[maxn*80],v[maxn],rt[maxn],siz[maxn],son[maxn];
    vector<int> ch[maxn];
    struct sag
    {
    	int ls,rs;
    }s[maxn*80];
    queue<int> q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    void insert(int &x,int y,int l,int r,int a,int b)
    {
    	x=++tot;
    	if(l==r)
    	{
    		add(x+n,b,1<<30);
    		if(y)	add(x+n,y+n,1<<30);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(a<=mid)	s[x].rs=s[y].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
    	else	s[x].ls=s[y].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
    }
    void getall(int x,int y)
    {
    	insert(rt[x],rt[x],1,n,v[y],y);
    	for(int i=0;i<(int)ch[y].size();i++)	getall(x,ch[y][i]);
    }
    void DFS(int x)
    {
    	siz[x]=1;
    	for(int i=0;i<(int)ch[x].size();i++)
    	{
    		DFS(ch[x][i]),siz[x]+=siz[ch[x][i]];
    		if(siz[ch[x][i]]>siz[son[x]])	son[x]=ch[x][i];
    	}
    	insert(rt[x],rt[son[x]],1,n,v[x],x);
    	for(int i=0;i<(int)ch[x].size();i++)	if(ch[x][i]!=son[x])	getall(x,ch[x][i]);
    }
    void query(int x,int l,int r,int a,int b,int y)
    {
    	if(!x)	return ;
    	if(a<=l&&r<=b)
    	{
    		add(y+n,x+n,1<<30);
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(a<=mid)	query(s[x].ls,l,mid,a,b,y);
    	if(b>mid)	query(s[x].rs,mid+1,r,a,b,y);
    }
    inline int dfs(int x,int mf)
    {
    	if(x==T)	return mf;
    	int i,k,temp=mf;
    	for(i=head[x];i!=-1;i=next[i])	if(d[to[i]]==d[x]+1&&val[i])
    	{
    		k=dfs(to[i],min(temp,val[i]));
    		if(!k)	d[to[i]]=0;
    		val[i]-=k,val[i^1]+=k,temp-=k;
    		if(!temp)	break;
    	}
    	return mf-temp;
    }
    int bfs()
    {
    	while(!q.empty())	q.pop();
    	memset(d,0,sizeof(d));
    	int i,u;
    	q.push(S),d[S]=1;
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])	if(!d[to[i]]&&val[i])
    		{
    			d[to[i]]=d[u]+1;
    			if(to[i]==T)	return 1;
    			q.push(to[i]);
    		}
    	}
    	return 0;
    }
    int main()
    {
    	//freopen("bz3681.out","w",stdout);
    	n=rd(),m=rd();
    	int i,a,b,x,y;
    	memset(head,-1,sizeof(head));
    	for(i=2;i<=n;i++)	fa[i]=rd(),ch[fa[i]].push_back(i);
    	for(i=1;i<=n;i++)	v[i]=rd();
    	DFS(1);
    	S=0;
    	for(i=1;i<=tot;i++)
    	{
    		if(s[i].ls)	add(i+n,s[i].ls+n,1<<30);
    		if(s[i].rs)	add(i+n,s[i].rs+n,1<<30);
    	}
    	for(i=1;i<=m;i++)
    	{
    		a=rd(),b=rd(),x=rd(),y=rd(),add(S,(++tot)+n,y);
    		query(rt[x],1,n,a,b,tot);
    	}
    	T=tot+n+1;
    	for(i=1;i<=n;i++)	add(i,T,1);
    	while(bfs())	ans+=dfs(S,1<<30);
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    PAT甲级——1095 Cars on Campus (排序、映射、字符串操作、题意理解)
    PAT甲级——1096 Consecutive Factors (数学题)
    PAT甲级——1097 Deduplication on a Linked List (链表)
    博客作业06--图
    博客作业05--查找
    博客作业04--树
    博客作业03--栈和队列
    博客作业2---线性表
    博客作业01-抽象数据类型
    C语言最后一次作业--总结报告
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7787178.html
Copyright © 2020-2023  润新知