[POI2015][bzoj4383] Pustynia [线段树优化建图+拓扑排序]

题面

bzoj权限题传送门

luogu传送门

思路

首先,这个题目显然可以从所有小的点往大的连边,然后如果没环就一定可行,从起点(入读为0)开始构造就好了

但是问题来了,如果每个都连的话,本题中边数是$O(n^2)$级别的,显然会挂

发现两条性质:

1.所有的限制条件中,给定的总点数不超过3e5个

2.是一个点比一段区间大

第二个条件决定了我们可以利用线段树优化建图,而第一个条件告诉了我们,本题的总边数应该是$sumk\astlog_2n$级别的

那么就做完了

注意拓扑排序的时候有个技巧,把连向实际的点的有向边边权标1,其他标0,这样方便处理

Code

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cassert>
#define ll long long
using namespace std;
inline int read(){
????int re=0,flag=1;char ch=getchar();
????while(ch>'9'||ch<'0'){
????????if(ch=='-') flag=-1;
????????ch=getchar();
????}
????while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
????return re*flag;
}
int n,m,s,first[1000010],ans[1000010],cnte,pos[1000010],cnt=0,in[1000010],is[1000010],isn[1000010];
struct edge{
????int to,next,w;
}a[8000010];
inline void add(int u,int v,int w){
????in[v]++;
????a[++cnte]=(edge){v,first[u],w};first[u]=cnte;
}
int q[1000010],dp[1000010];
namespace seg{
????int ch[400010][2];
????int build(int l,int r){
????????int cur=++cnt;is[cur]=1;
????????if(l==r){
????????????isn[cur]=1;
????????????return pos[l]=cur;
????????}
????????int mid=(l+r)>>1;
????????ch[cur][0]=build(l,mid);
????????ch[cur][1]=build(mid+1,r);
????????add(ch[cur][0],cur,0);
????????add(ch[cur][1],cur,0);
????????return cur;
????}
????void change(int l,int r,int ql,int qr,int cur,int ori){
????????if(ql>qr) return;
????????if(l>=ql&&r<=qr){
????????????add(cur,ori,1);return;
????????}
????????int mid=(l+r)>>1;
????????if(mid>=ql) change(l,mid,ql,qr,ch[cur][0],ori);
????????if(mid<qr) change(mid+1,r,ql,qr,ch[cur][1],ori);
????}
}
void topo(){
????int i,u,v,head=0,tail=0,tot=0;
????for(i=1;i<=cnt;i++) if(!in[i]){
????????q[tail++]=i;dp[i]=1;
????}
????while(head<tail){
????????u=q[head++];tot+=isn[u];
????????if(dp[u]>1e9){
????????????puts("NIE");return;
????????}
????????if((!is[u])&&(dp[u]>ans[u])){
????????????puts("NIE");return;
????????}
????????if((!is[u])&&(dp[u]<ans[u])) dp[u]=ans[u];
????????for(i=first[u];~i;i=a[i].next){
????????????v=a[i].to;
????????????if(dp[v]<dp[u]+a[i].w){
????????????????dp[v]=dp[u]+a[i].w;
????????????}
????????????if(!(--in[v])) q[tail++]=v;
????????}
????}
????if(tot<n){
????????puts("NIE");return;
????}
????puts("TAK");
????for(i=1;i<=n;i++) printf("%d ",dp[pos[i]]);
}
int main(){
????memset(first,-1,sizeof(first));
????n=read();s=read();m=read();int i,j,t1,t2,t3;
????memset(ans,63,sizeof(ans));
????int root=seg::build(1,n);
????for(i=1;i<=s;i++){
????????t1=read();t2=read();
????????ans[pos[t1]]=t2;is[pos[t1]]=0;
????}
????for(i=1;i<=m;i++){
????????t1=read();t2=read();t3=read();
????????cnt++;is[cnt]=1;
????????for(j=1;j<=t3;j++) q[j]=read(),add(cnt,pos[q[j]],0);
????????seg::change(1,n,t1,q[1]-1,root,cnt);
????????seg::change(1,n,q[t3]+1,t2,root,cnt);
????????for(j=1;j<t3;j++) seg::change(1,n,q[j]+1,q[j+1]-1,root,cnt);
????}
????topo();
}

原文地址:https://www.cnblogs.com/dedicatus545/p/9603515.html

时间: 2024-10-08 06:38:17

[POI2015][bzoj4383] Pustynia [线段树优化建图+拓扑排序]的相关文章

[bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][Discuss] Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi?Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? Inp

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

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

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

【ARC069F】Flags 2-sat+线段树优化建图+二分

Description ? 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ? 第一行一个整数 N. ? 接下来 N 行每行两个整数 xi,yi Output ? 一个整数表示答案. Sample Input Sample #1 3 1 3 2 5 1 9 Sample #2 5 2 2 2 2 2 2 2 2 2 2 Sample #3 22 93 6440 78 6647 862 11 8306 9689 798 99 801 52

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

一个神秘的oj2587 你猜是不是dp(线段树优化建图)

哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T,连流量为收益 这不就结束了吗? 自信写完,提交 woc!!只有40分? #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>

机房测试5:reverse(bfs+set 或 线段树优化建图)

题目: 分析: 首先画样例分析一下,会发现如果要求一个位置要多少次翻转,就将这个位置向与它关联的点连边(关联点指的是可能与它值互换的位置),一直连到起点为止,连边的次数即为它所需步数. 所以转换成求单源最短路,因为边权为1,可以用bfs. 但是这道题n的范围很大,刚刚的做法是n*k的,考虑优化. 法1:在建图上优化 题目要求的是区间翻转,所以也对应着相关性质:每个点连边一定是都连的奇数点或偶数点(画图可知),且这些奇数偶数点都对应着一段连续的区间. 如果可以将点向点连边优化成点向区间连边,复杂度

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)