bzoj 3681 Arietta

http://www.elijahqi.win/archives/3351
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

考虑可以怎么做 题目相当于每次向一棵子树内的所有权值在一个区间范围内的点连边 然后每个点出边的最大容量为1 那么跑最大流即可 但是因为复杂度是n*m的显然是不可以接受的那么不妨考虑优化建图 那么就在每个节点维护以权值为下标的线段树 有个显然的做法就是像par树一样从底向上合并上来但这题不可以 因为一个权值可能多个出边 并且这样似乎复杂度不对?

那么就考虑主席树的做法 首先针对原树进行轻重链的划分 然后每个节点直接从子树重儿子继承过来 然后其他轻儿子就用启发式合并即可 可以证明这个复杂度是log^2的 即 点数 n*log(n)^2+n+m 边数 2*n*log(n)^2+m*log(n)

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e4+10;
const int NN=1300010;
const int inf=0x3f3f3f3f;
struct node{
    int y,next,z;
}data[NN<<1];
struct node1{
    int left,right;
}tree[NN];
int num=1,rt[N],H[N],h[NN],size[N],cnt,level[NN],T,n,m,cur[NN];
vector<int>son[N];
inline void insert2(int x,int y,int z){
    data[++num].y=y;data[num].next=h[x];data[num].z=z;h[x]=num;
    data[++num].y=x;data[num].next=h[y];data[num].z=0;h[y]=num;
}
inline bool bfs(){
    queue<int>q;q.push(0);memset(level,0,sizeof(level));level[0]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=h[x];i;i=data[i].next){
            int y=data[i].y,z=data[i].z;
            if (level[y]||!z) continue;level[y]=level[x]+1;if (y==T) return 1;q.push(y);
        }
    }return 0;
}
inline int dfs(int x,int s){
    if (x==T) return s;int ss=s;
    for (int &i=cur[x];i;i=data[i].next){
        int y=data[i].y,z=data[i].z;
        if (level[x]+1==level[y]&&z){
            int xx=dfs(y,min(z,s));if (!xx) level[y]=0;
            s-=xx;data[i].z-=xx;data[i^1].z+=xx;if (!s) return ss;
        }
    }return ss-s;
}
inline void insert1(int &x,int l,int r,int p,int id){
    tree[++cnt]=tree[x];if (x)insert2(cnt+n,x+n,inf);x=cnt;
    if(l==r) {insert2(x+n,id,inf);return;}int mid=l+r>>1;
    if (p<=mid) insert1(tree[x].left,l,mid,p,id),insert2(x+n,tree[x].left+n,inf);
    if (p>mid) insert1(tree[x].right,mid+1,r,p,id),insert2(x+n,tree[x].right+n,inf);

}
inline void dfs1(int x,int id){
    insert1(rt[id],1,n,H[x],x);
    for (int i=0;i<son[x].size();++i) dfs1(son[x][i],id);
}
inline void dfs_init(int x){
    size[x]=1;int mx=0,mxid=0;
    for (int i=0;i<son[x].size();++i){
        int y=son[x][i];dfs_init(y);
        size[x]+=size[y];if(size[y]>mx) mx=size[y],mxid=y;
    }rt[x]=rt[mxid];insert1(rt[x],1,n,H[x],x);
    for (int i=0;i<son[x].size();++i){
        int y=son[x][i];if (y==mxid) continue;dfs1(y,x);
    }
}
inline void modify(int x,int l,int r,int l1,int r1){
    if (!x) return;
    if(l1<=l&&r1>=r){insert2(cnt+n,x+n,inf);return;}int mid=l+r>>1;
    if (l1<=mid) modify(tree[x].left,l,mid,l1,r1);
    if (r1>mid) modify(tree[x].right,mid+1,r,l1,r1);
}
int main(){
    freopen("bzoj3681.in","r",stdin);
    n=read();m=read();
    for (int i=2;i<=n;++i) son[read()].push_back(i);
    for (int i=1;i<=n;++i) H[i]=read();dfs_init(1);
    for (int i=1;i<=m;++i){
        int l=read(),r=read(),d=read(),t=read();
        ++cnt;insert2(0,cnt+n,t);modify(rt[d],1,n,l,r);
    }T=cnt+1+n;int ans=0;
    for (int i=1;i<=n;++i) insert2(i,T,1);
    /*for (int i=2;i<=num;++i){
        printf("%d %d %d\n",data[i].x,data[i].y,data[i].z);
    }*/
    while(bfs()) memcpy(cur,h,sizeof(h)),ans+=dfs(0,inf);
    printf("%d\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值