zoukankan      html  css  js  c++  java
  • 【BZOJ-3681】Arietta 网络流 + 线段树合并

    3681: Arietta

    Time Limit: 20 Sec  Memory Limit: 64 MB
    Submit: 182  Solved: 70
    [Submit][Status][Discuss]

    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

    Source

    Shinrein祭 #1

    Solution

    怎么看都和A+B problem很类似,所以肯定是 主席树优化构图 + 网络流

    这样的树形态主席树,用线段树合并会很方便得到每个子树对应的主席树形态,注意一下细节就好了,数组大小得斟酌着开!!!..

    这样的话,点数大概是$O(2NlogN+M)$级,边数大概在$O(2NlogN+MlogL)$级。

    但是这题内存64M还是有点小卡的..一开始没有判断lson和rson是否存在就直接连边了,造成连了大量无用的边,MLE了一次,在连边的时候注意一下是否有意义即可。

    不知道程序里好像有什么奇怪的地方..本机拍一组大样例RE..因为连边时有某个点编号连完后变大了10倍..其余的应该是没什么问题..谁知道这沙茶程序出了啥毛病(捂脸

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1; char ch=getchar();
    	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    	return x*f;
    }
    
    #define MAXN 400010
    #define INF 0x7fffffff
    
    int N,M,sz=1;
    
    struct EdgeNode{
    	int next,to,cap;
    }edge[1000010];
    int head[MAXN],cnt=1;
    inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
    inline void InsertEdge(int u,int v,int w) {/*printf("<%d,%d>%d
    ",u,v,w);*/ AddEdge(u,v,w); AddEdge(v,u,0);}
    
    int h[MAXN],cur[MAXN],S,T;
    queue<int>q;
    inline bool Bfs()
    {
        for (int i=0; i<=sz; i++) h[i]=-1;
        q.push(S); h[S]=0;
        while (!q.empty()) {
            int now=q.front(); q.pop();
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].cap && h[edge[i].to]==-1)
                    h[edge[i].to]=h[now]+1,q.push(edge[i].to);
        }
        return h[T]!=-1;
    }
     
    inline int Dfs(int now,int low)
    {
        if (now==T) return low;
        int w,used=0;
        for (int i=cur[now]; i; i=edge[i].next)
            if (edge[i].cap && h[edge[i].to]==h[now]+1) {
                int w=Dfs(edge[i].to,min(low-used,edge[i].cap));
                edge[i].cap-=w; edge[i^1].cap+=w; used+=w;
                if (used==low) return used;
                if (edge[i].cap) cur[now]=i;
            }
        if (!used) h[now]=-1;
        return used;
    }
     
    inline int Dinic()
    {
        int re=0;
        while (Bfs()) {
            for (int i=0; i<=sz; i++) cur[i]=head[i];
            re+=Dfs(S,INF);
        }
        return re;
    }
    
    struct SgtNode{
    	int lson,rson;
    }tree[10010*80];
    
    int root[MAXN];
    inline void Insert(int &x,int l,int r,int pos)
    {
    	x=++sz;
    	if (l==r) {
    		InsertEdge(x,T,1);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (pos<=mid) Insert(tree[x].lson,l,mid,pos),InsertEdge(x,tree[x].lson,INF);
    		else Insert(tree[x].rson,mid+1,r,pos),InsertEdge(x,tree[x].rson,INF);
    }
    
    inline int Merge(int x,int y,int l,int r)
    {
    	if (!x || !y) return x|y;
    	int z=++sz;
    	if (l==r) {
    		InsertEdge(z,x,INF),InsertEdge(z,y,INF);
    		return z;
    	}
    	int mid=(l+r)>>1;
    	tree[z].lson=Merge(tree[x].lson,tree[y].lson,l,mid);
    	if (tree[z].lson) InsertEdge(z,tree[z].lson,INF);
    	tree[z].rson=Merge(tree[x].rson,tree[y].rson,mid+1,r);
    	if (tree[z].rson) InsertEdge(z,tree[z].rson,INF);
    	return z;
    }
    
    inline void Query(int x,int l,int r,int L,int R,int id)
    {
    	if (!x) return;
    	if (L<=l && R>=r) {
    		InsertEdge(id,x,INF);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if (L<=mid) Query(tree[x].lson,l,mid,L,R,id);
    	if (R>mid) Query(tree[x].rson,mid+1,r,L,R,id);
    }
    
    vector<int>son[MAXN];
    inline void DFS(int now)
    {
    	for (int i=0; i<son[now].size(); i++) {
    		DFS(son[now][i]);
    		root[now]=Merge(root[now],root[son[now][i]],1,N);
    	}
    }
    
    int main()
    {
    	
    	N=read(),M=read();
    	
    	for (int i=2,x; i<=N; i++) x=read(),son[x].push_back(i);
    	
    	S=0,T=1;
    	
    	for (int i=1,x; i<=N; i++) x=read(),Insert(root[i],1,N,x);
    	
    	DFS(1);
    	
    	for (int i=1; i<=M; i++) {
    		int L=read(),R=read(),D=read(),Ti=read();
    		InsertEdge(S,++sz,Ti); Query(root[D],1,N,L,R,sz);
    	}
    	
    	printf("%d
    ",Dinic());
    	
    	return 0;
    }
    

      

  • 相关阅读:
    SpringCloud笔记(一)服务注册与发现
    个人备忘录
    ActiveMQ 消息持久化到Mysql数据库
    染色 [组合数 容斥]
    各种图床
    NOIP2012 疫情控制
    网格计数
    找钱 [多重背包 计数]
    序列[势能线段树]
    牛客挑战赛33 B-鸽天的放鸽序列
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/6621194.html
Copyright © 2011-2022 走看看