P3588 【[POI2015]PUS】

终于有个能让我一遍过的题了,写篇题解纪念一下

给定长度为n的序列和其中部分已知的数,还有m个大小关系:区间\([l,r]\)中,有k个给定的数比剩下的\(r-l+1-k\)个数都大

求是否有解,有解给出任意一个合法方案

按大小关系,从大的数向小的数连边

直接建图肯定不行,考虑用线段树优化,如果你不会线段树优化建边,点这里

对于每个\([l,r]\)的区间,这k个给定的数会把区间分成\(k+1\)个小区间

新建一个虚拟节点,这k个数分别向虚拟节点连边,这个虚拟节点再通过线段树向\(k+1\)个小区间连边

 

有环会出现自己大于自己的情况,要先判掉

再拓扑排序,求一种序列

先把未给出的数赋值为1e9,然后对于每一条u->v的边,a[v]=min(a[v],a[u]-len[i])len[i]为边权

线段树中的边是虚构的只是为了让它联通起来,所以边权为0,实际的边边权为1,也就是a[v]至少比a[u]少1

如果出现a[v]为给定的数,且a[v]>a[u]-len[i],则找不出合法方案

如果出现了a[v]<0的情况,超出题目要求的值域,无解

剩下的在注释里

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<iomanip>
#include<cstring>
#define R register
#define EN std::puts("")
#define LL long long
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,s,m,nn;
int a[2000006],should[2000006];//should[i]=1,说明i号数字为给定的数字
int in[2000006];
struct tr{
tr *ls,*rs;
int id;
}dizhi[2000006],*root=&dizhi[0];
int tot;
int fir[2000006],to[2000006],nex[2000006],len[2000006];
int etot;
int vis[2000006],instack[2000006];//vis标记是否被访问,instack标记是否在栈中
int huan;//记录是否有环
void dfs(int u){
vis[u]=instack[u]=1;
for(R int i=fir[u];i;i=nex[i]){
if(instack[to[i]]) huan=1;//遇到已经在栈中节点,说明有环
if(!vis[to[i]]) dfs(to[i]);
}
instack[u]=0;
}
inline void add(int u,int v,int x){
to[++etot]=v;len[etot]=x;
nex[etot]=fir[u];fir[u]=etot;
}
void build(tr *tree,int l,int r){
if(l==r){tree->id=l;return;}
int mid=(l+r)>>1;
tree->ls=&dizhi[++tot];tree->rs=&dizhi[++tot];
build(tree->ls,l,mid);build(tree->rs,mid+1,r);
tree->id=++nn;
// std::printf("block %d %d id:%d\n",l,r,tree->id);
add(tree->id,tree->ls->id,0);add(tree->id,tree->rs->id,0);
in[tree->ls->id]++;in[tree->rs->id]++;
}
void addtree(tr *tree,int l,int r,int ql,int qr,int u){
if(ql<=l&&r<=qr){add(u,tree->id,0);in[tree->id]++;return;}//在由k个点向虚拟节点连边时建的边边权为1,所以这里要建边权为0的边
int mid=(l+r)>>1;
if(ql<=mid) addtree(tree->ls,l,mid,ql,qr,u);
if(qr>mid) addtree(tree->rs,mid+1,r,ql,qr,u);
}
std::queue<int>q;
inline void topo(){
for(R int i=1;i<=nn;i++) if(!a[i])a[i]=1e9;//先把为给定的数设为最大
for(R int i=1;i<=nn;i++) if(!in[i])q.push(i);
while(!q.empty()){
R int u=q.front();q.pop();
for(R int i=fir[u];i;i=nex[i]){
int v=to[i];
if(should[v]){
if(a[v]>a[u]-len[i]){std::puts("NIE");std::exit(0);}
}
else a[v]=std::min(a[v],a[u]-len[i]);
if(a[v]<1){std::puts("NIE");std::exit(0);}//超出值域
if(!--in[v]) q.push(v);
}
}
}
int main(){
nn=n=read();s=read();m=read();
for(R int i=1;i<=s;i++){
int pos=read();
a[pos]=read();should[pos]=1;
}
build(root,1,n);
while(m--){
int l=read(),r=read(),k=read();nn++;
R int last=l,x;
for(R int j=1;j<=k;j++){
x=read();
add(x,nn,1);in[nn]++;
if(x>last) addtree(root,1,n,last,x-1,nn);
last=x+1;
}
if(last<=r) addtree(root,1,n,last,r,nn);
}
for(R int i=1;i<=n;i++)if(!vis[i]){
huan=0;dfs(i);
if(huan){std::puts("NIE");std::exit(0);}
}
topo();
std::puts("TAK");
for(R int i=1;i<=n;i++) std::printf("%d ",a[i]);
// EN;
// for(R int i=1;i<=nn;i++){
// std::printf("%d:",i);
// for(R int j=fir[i];j;j=nex[j]){
// std::printf("(%d %d) ",to[j],len[j]);
// }
// EN;
// }
return 0;
}

P3588 【[POI2015]PUS】(线段树优化建边)的更多相关文章

  1. [POI2015]PUS [线段树优化建图]

    problem 线段树优化建图,拓扑,没了. #include <bits/stdc++.h> #define ls(x) ch[x][0] #define rs(x) ch[x][1] ...

  2. BZOJ_4383_[POI2015]Pustynia_线段树优化建图+拓扑排序

    BZOJ_4383_[POI2015]Pustynia_线段树优化建图+拓扑排序 Description 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息 ...

  3. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

  4. BZOJ4383 [POI2015]Pustynia[线段树优化建边+拓扑排序+差分约束]

    收获挺大的一道题. 这里的限制大小可以做差分约束,从$y\to x$连$1$,表示$y\le x-1$即$y<x$,然后跑最长路求解. 但是,如果这样每次$k+1$个小区间每个点都向$k$个断点 ...

  5. 洛谷P3588 [POI2015]PUS(线段树优化建图)

    题面 传送门 题解 先考虑暴力怎么做,我们把所有\(r-l+1-k\)中的点向\(x\)连有向边,表示\(x\)必须比它们大,那么如果这张图有环显然就无解了,否则的话我们跑一个多源最短路,每个点的\( ...

  6. UOJ#77. A+B Problem [可持久化线段树优化建边 最小割]

    UOJ#77. A+B Problem 题意:自己看 接触过线段树优化建图后思路不难想,细节要处理好 乱建图无果后想到最小割 白色和黑色只能选一个,割掉一个就行了 之前选白色必须额外割掉一个p[i], ...

  7. Codeforces 1045. A. Last chance(网络流 + 线段树优化建边)

    题意 给你 \(n\) 个武器,\(m\) 个敌人,问你最多消灭多少个敌人,并输出方案. 总共有三种武器. SQL 火箭 - 能消灭给你集合中的一个敌人 \(\sum |S| \le 100000\) ...

  8. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

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

    [BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...

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

    Description ​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ​ 第一行一个整数 N. ​ 接下来 N 行每行两个整数 xi, ...

随机推荐

  1. C语言 文件操作(一)

    #include<stdio.h> int main(){          FILE *fp = fopen("f:\\lanyue.txt","r&quo ...

  2. C#使用HTML文件中的file文件上传,用C#代码接收上传文件

    单独做图片上传很简单,如果要客户端要上传头像保存到服务器就要稍微麻烦一点点了. 不多说了,直接上源码: private void Upload() { string jsonInfo = string ...

  3. MySQL学习之路7-索引、事务、函数、存储过程、游标

    索引 使用索引快速定位某列中特定值的行,不需要遍历数据表所有行. 创建索引的数据结构:BTREE and HASH. 主键也是一种索引,Primary key. show index from ord ...

  4. 如何关闭php的所有错误提示

    在调试PHP 应用程序时,应当知道两个配置变量.下面是这两个变量及其默认值:display_errors = Offerror_reporting = E_ALL E_ALL能从不良编码实践到无害提示 ...

  5. Redis cluster集群配置教程

    这里建议大家安装4.0.9版本的 1.打开Centos虚拟机,登陆. 2.通过WinSCP把Redis集群tar包上传到虚拟机里的目录里,我的目录是 /usr/local 这里我已经上传过了并解压了, ...

  6. Vue 核心最基本的功能

    ~~~<html><head> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"& ...

  7. Maven版本不合适导致出现的问题如下,换个老版本就好了

    2019-09-30 11:56:24,555 [ 597097] ERROR - #org.jetbrains.idea.maven - IntelliJ IDEA 2018.3.5 Build # ...

  8. 委托的 `DynamicInvoke` 小优化

    委托的 DynamicInvoke 小优化 Intro 委托方法里有一个 DynamicInvoke 的方法,可以在不清楚委托实际类型的情况下执行委托方法,但是用 DynamicInvoke 去执行的 ...

  9. stand up meeting 12/4/2015 -12/6/2015

    part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云        ------  --- 数据库 朱玉影  等待张葳出关        0  foxit reader  6 ...

  10. div3--D - Distinct Characters Queries

    题目链接:https://codeforces.com/contest/1234/problem/D 题目大意: 对于给定的字符串,给出n个查询,查询时输入3个数啊,a,b,c,如果说a==1,则将位 ...