线段树建边

struct E
{
int value, modvalue;
} a[MAXN << ];
pair<int, int> b[MAXN];
int root, l[MAXN << ], r[MAXN << ], tot;
int build(int a, int b)
{
int x;
if (a == b)
{
x =::b[a].second;
}
else
{
x = ++tot;
}
if (a == b)
{
return x;
}
int mid = (a + b) >> ;
l[x] = build(a, mid);
r[x] = build(mid + , b);
addedge(x, l[x]);
addedge(x, r[x]);
return x;
}
void ins(int x, int a, int b, int c, int d, int p)
{
if (d < c)
{
return ;
}
if (c <= a && b <= d)
{
addedge(p, x);
return;
}
int mid = (a + b) >> ;
if (c <= mid)
{
ins(l[x], a, mid, c, d, p);
}
if (d > mid)
{
ins(r[x], mid + , b, c, d, p);
}
}

A

如果把边数缩小到n^2可以接受的话 就是一个最小点基的裸题

但是这里可能有n^2条边所以我们需要线段树优化建边 然后再求出SCC

扣掉不包含原始n个节点的SCC或者把除叶子节点外线段树上的点权设为inf 然后跑最小点基

claris姐姐版SCC缩点:

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int, int> P;
const int N = , M = ;
int n, m, i, j, x, y;
long long ans;
struct E
{
int p, r, c;
} a[N];
P b[N];
int root, l[N], r[N], tot;
set<P>T[N];
int g[][N], nxt[][M], v[][M], ed, f[N], q[N], t, vis[N], ban[N];
inline void add(int x, int y)
{
v[][++ed] = y;
nxt[][ed] = g[][x];
g[][x] = ed;
v[][ed] = x;
nxt[][ed] = g[][y];
g[][y] = ed;
}
inline void ADD(int x, int y)
{
v[][++ed] = y;
nxt[][ed] = g[][x];
g[][x] = ed;
}
int build(int a, int b)
{
int x;
if (a == b) //如果该点是叶子节点的话 值就为下标
{
x =::b[a].second;
}
else //否则的话 就给该节点一个标号
{
x = ++tot;
}
if (a == b)
{
return x;
}
int mid = (a + b) >> ;
l[x] = build(a, mid);
r[x] = build(mid + , b);
add(x, l[x]);
add(x, r[x]);
return x;
}
void ins(int x, int a, int b, int c, int d, int p)
{
if (c <= a && b <= d)
{
add(p, x); //p是不会变的 如果满足条件的话就把p和x节点连上一条边
return;
}
int mid = (a + b) >> ;
if (c <= mid)
{
ins(l[x], a, mid, c, d, p);
}
if (d > mid)
{
ins(r[x], mid + , b, c, d, p);
}
}
inline int askl(int x) //min >=x
{
int l = , r = n, mid, t;
while (l <= r)
{
mid = (l + r) >> ;
if (b[mid].first >= x)
{
r = (t = mid) - ;
}
else
{
l = mid + ;
}
}
return t;
}
inline int askr(int x) //max <=x
{
int l = , r = n, mid, t;
while (l <= r)
{
mid = (l + r) >> ;
if (b[mid].first <= x)
{
l = (t = mid) + ;
}
else
{
r = mid - ;
}
}
return t;
}
void dfs1(int x)
{
vis[x] = ;
for (int i = g[][x]; i; i = nxt[][i])
if (!vis[v[][i]])
{
dfs1(v[][i]);
}
q[++t] = x;
}
void dfs2(int x, int y)
{
vis[x] = ;
f[x] = y;
for (int i = g[][x]; i; i = nxt[][i])
if (vis[v[][i]])
{
dfs2(v[][i], y);
}
}
void dfs3(int x)
{
if (ban[x])
{
return;
}
ban[x] = ;
for (int i = g[][x]; i; i = nxt[][i])
{
dfs3(v[][i]);
}
}
inline void solve(int x)
{
if (vis[x])
{
return;
}
vis[x] = ;
for (int i = g[][x]; i; i = nxt[][i])
{
dfs3(v[][i]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (i = ; i <= n; i++)
{
scanf("%d%d%d", &a[i].p, &a[i].r, &a[i].c);
b[i] = P(a[i].p, i);
}
sort(b + , b + n + ); //根据每个点的位置进行排序
tot = n; //初始会有n个节点
root = build(, n); //建立线段树并对线段树上的节点进行赋值
for (i = ; i <= n; i++)
{
int l = askl(a[i].p - a[i].r); //二分得到最左边炸到的节点
int r = askr(a[i].p + a[i].r); //二分得到最右边炸到的节点
ins(root, , n, l, r, i); //把该节点和线段树上范围为子区间的节点连一条边
}
for (t = , i = ; i <= tot; i++)
if (!vis[i])
{
dfs1(i);
}
for (i = tot; i; i--)
if (vis[q[i]])
{
dfs2(q[i], q[i]);
}
ed = ; //ed为SCC的边总数
for (i = ; i <= tot; i++) //SCC前向星初始化head数组
{
g[][i] = ;
}
for (i = ; i <= tot; i++)
for (j = g[][i]; j; j = nxt[][j])
if (f[i] != f[v[][j]]) //不同SCC之间建边
{
ADD(f[i], f[v[][j]]);
}
for (i = ; i <= n; i++)
{
solve(f[i]);
}
for (i = ; i <= n; i++)
if (!ban[f[i]]) //如果f[i]这个SCC是合法的话 就插入该点的一个值
{
T[f[i]].insert(P(a[i].c, i));
}
for (i = ; i <= tot; i++)
if (!ban[i] && f[i] == i) //如果这个SCC合法且这个SCC的入度是0的话 就把这个SCC内最小的点权值加上
{
ans += T[i].begin()->first;
}
while (m--)
{
scanf("%d%d", &x, &y);
if (!ban[f[x]]) //
{
ans -= T[f[x]].begin()->first;
T[f[x]].erase(P(a[x].c, x));
T[f[x]].insert(P(a[x].c = y, x));
ans += T[f[x]].begin()->first;
}
printf("%lld\n", ans);
}
}

自己写的:

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + ;
const int gakki = + + + + 1e9;
const int MAXN = 5e5 + , MAXM = 3e6 + ;
int to[MAXM << ], nxt[MAXM << ], Head[MAXN], ed = ;
typedef pair<int, int> P;
const int N = , M = ;
int n, m, i, j, x, y;
long long ans;
struct E
{
int p, r, c;
} a[N];
P b[N];
int to2[MAXM << ], nxt2[MAXM << ], Head2[MAXN];
int ed2 = ;
int root, l[N], r[N], tot;
//set<P> T[N];
int t;
int value[N];
set<P> valuemin[N];
inline void addedge(int u, int v)
{
to[++ed] = v;
nxt[ed] = Head[u];
Head[u] = ed;
}
inline void addedge2(int u, int v)
{
to2[++ed2] = v;
nxt2[ed2] = Head2[u];
Head2[u] = ed2;
}
//inline void add(int x, int y)
//{
// v[0][++ed] = y;
// nxt[0][ed] = g[0][x];
// g[0][x] = ed;
// v[1][ed] = x;
// nxt[1][ed] = g[1][y];
// g[1][y] = ed;
//}
//inline void ADD(int x, int y)
//{
// v[1][++ed] = y;
// nxt[1][ed] = g[1][x];
// g[1][x] = ed;
//}
int build(int a, int b)
{
int x;
if (a == b)
{
x =::b[a].second;
}
else
{
x = ++tot;
}
if (a == b)
{
return x;
}
int mid = (a + b) >> ;
l[x] = build(a, mid);
r[x] = build(mid + , b);
addedge(x, l[x]);
addedge(x, r[x]);
return x;
}
void ins(int x, int a, int b, int c, int d, int p)
{
if (c <= a && b <= d)
{
addedge(p, x);
return;
}
int mid = (a + b) >> ;
if (c <= mid)
{
ins(l[x], a, mid, c, d, p);
}
if (d > mid)
{
ins(r[x], mid + , b, c, d, p);
}
}
inline int askl(int x) //min >=x
{
int l = , r = n, mid, t;
while (l <= r)
{
mid = (l + r) >> ;
if (b[mid].first >= x)
{
r = (t = mid) - ;
}
else
{
l = mid + ;
}
}
return t;
}
inline int askr(int x) //max <=x
{
int l = , r = n, mid, t;
while (l <= r)
{
mid = (l + r) >> ;
if (b[mid].first <= x)
{
l = (t = mid) + ;
}
else
{
r = mid - ;
}
}
return t;
}
int dfn[MAXN];//表示这个点在dfs的时候是第几个搜到的;
int low[MAXN];//表示这个点及其子节点连的所有点里dfn的最小值
int sta[MAXN];//存着当前所有可能能构成强连通分量的点
int visit[MAXN];//表示一个点目前是否在sta中
int color[MAXN];//表示一个点属于哪个强连通分量
int deep;/*表示从前有多少个点被搜到*/
int top;/*sta目前的大小*/
int colorsum = ;/*目前强连通分量的数目*/
int rudu[MAXN];
int ok[N];
queue<int> q, anser;
void tarjan(int x)
{
dfn[x] = ++deep;
low[x] = deep;
visit[x] = ;
sta[++top] = x;
for (int i = Head[x]; i; i = nxt[i])
{
int v = to[i];
if (!dfn[v])
{
tarjan(v);
low[x] = min(low[x], low[v]);
}
else
{
if (visit[v])
{
low[x] = min(low[x], low[v]);
}
}
}
if (dfn[x] == low[x])
{
color[x] = ++colorsum;
visit[x] = ;
while (sta[top] != x)
{
color[sta[top]] = colorsum;
visit[sta[top--]] = ;
}
top--;
}
}
inline void read(int &v)
{
v = ;
char c = ;
int p = ;
while (c < '' || c > '')
{
if (c == '-')
{
p = -;
}
c = getchar();
}
while (c >= '' && c <= '')
{
v = (v << ) + (v << ) + c - '';
c = getchar();
}
v *= p;
}
int main()
{
read(n), read(m);
for (i = ; i <= n; i++)
{
read(a[i].p), read(a[i].r), read(a[i].c);
b[i] = P(a[i].p, i);
}
sort(b + , b + n + );
tot = n;
root = build(, n);
for (i = ; i <= n; i++)
{
int l = askl(a[i].p - a[i].r);
int r = askr(a[i].p + a[i].r);
ins(root, , n, l, r, i);
}
for (int i = ; i <= tot; i++)
{
if (i <= n)
{
value[i] = a[i].c;
}
else
{
value[i] = INT_MAX;
}
}
for (int i = ; i <= tot; i++)
{
if (!dfn[i])
{
tarjan(i);
}
}
for (int i = ; i <= tot; i++)
{
valuemin[color[i]].insert(make_pair(value[i], i));
for (int j = Head[i]; j; j = nxt[j])
{
int v = to[j];
if (color[v] != color[i])
{
rudu[color[v]]++;
addedge2(color[i], color[v]);
}
}
}
for (int i = ; i <= colorsum; i++)
{
if (rudu[i] == )
{
q.push(i);
}
}
while (!q.empty())
{
int now = q.front();
q.pop();
if (valuemin[now].begin()->first != INT_MAX)
{
anser.push(now);
}
else
{
for (int i = Head2[now]; i; i = nxt2[i])
{
int v = to2[i];
rudu[v]--;
if (rudu[v] == )
{
q.push(v);
}
}
}
}
while (!anser.empty())
{
int now = anser.front();
anser.pop();
ans += valuemin[now].begin()->first;
ok[now] = ;
//cout << now << "!!!" << endl;
}
int mi, ci;
while (m--)
{
read(mi), read(ci);
if (ok[color[mi]])
{
ans -= 1LL * valuemin[color[mi]].begin()->first;
valuemin[color[mi]].erase(make_pair(a[mi].c, mi));
a[mi].c = ci;
valuemin[color[mi]].insert(make_pair(a[mi].c, mi));
ans += 1LL * valuemin[color[mi]].begin()->first;
}
cout << ans << endl;
}
}

牛客第四场 J

先线段树优化建边 然后把整个图扣下来拓扑排序 要判两种-1的情况

第一种是insert的时候区间里有-1 用前缀和来判

第二种是拓扑排序的时候有环 用最终答案的size来判

/*Huyyt*/
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + ;
const int gakki = + + + + 1e9;
const int MAXN = 8e6 + , MAXM = 1e7 + ;
int to[MAXM << ], nxt[MAXM << ], Head[MAXN], ed = ;
typedef pair<int, int> P;
const int N = , M = ;
int n, m, i, j, x, y;
long long ans;
struct E
{
int value, modvalue;
} a[N];
P b[N];
int pre[N], flag = ;
int number = ;
int wait[N];
int root, l[N], r[N], tot;
queue<int> finalans;
bool visit[N];
int du[N];
int sum = ;
int nowmod;
int nowvalue[N];
int t;
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
inline void addedge(int u, int v)
{
du[v]++;
to[++ed] = v;
nxt[ed] = Head[u];
Head[u] = ed;
}
int build(int a, int b)
{
int x;
if (a == b)
{
x =::b[a].second;
}
else
{
x = ++tot;
}
if (a == b)
{
return x;
}
int mid = (a + b) >> ;
l[x] = build(a, mid);
r[x] = build(mid + , b);
addedge(l[x], x);
addedge(r[x], x);
return x;
}
void ins(int x, int a, int b, int c, int d, int p)
{
if (d < c)
{
return ;
}
if (c <= a && b <= d)
{
//cout << "add " << x << " " << p << " l r " << l[x] << " " << r[x] << endl;
addedge(x, p);
return;
}
int mid = (a + b) >> ;
if (c <= mid)
{
ins(l[x], a, mid, c, d, p);
}
if (d > mid)
{
ins(r[x], mid + , b, c, d, p);
}
}
inline void read(int &v)
{
v = ;
char c = ;
int p = ;
while (c < '' || c > '')
{
if (c == '-')
{
p = -;
}
c = getchar();
}
while (c >= '' && c <= '')
{
v = (v << ) + (v << ) + c - '';
c = getchar();
}
v *= p;
}
void get_du(int x)
{
//wait[++number] = x;
visit[x] = true;
for (int v, i = Head[x]; i; i = nxt[i])
{
v = to[i];
du[v]++;
if (!visit[v])
{
get_du(v);
}
}
}
void init(int x)
{
pre[] = number = ;
sum = ;
flag = ed = ;
for (int i = ; i <= x + ; i++)
{
visit[i] = Head[i] = du[i] = ;
}
}
int main()
{
int T;
read(T);
while (T--)
{
read(n);
for (i = ; i <= n; i++)
{
pre[i] = pre[i - ];
read(a[i].value);
if (a[i].value != -)
{
sum++;
}
else
{
pre[i]++;
}
a[i].modvalue = i - ;
b[i] = P(a[i].modvalue, i);
}
tot = n;
if (sum == )
{
cout << endl;
init(tot);
continue;
}
root = build(, n);
for (i = ; i <= n; i++)
{
if (a[i].value != -)
{
nowmod = a[i].value % n;
if (a[i].modvalue > nowmod)
{
//printf("ins %d %d %d\n", i, nowmod + 1, a[i].modvalue);
if (a[i].modvalue >= nowmod + && pre[a[i].modvalue] - pre[nowmod] != )
{
flag = ;
break;
}
ins(root, , n, nowmod + , a[i].modvalue, i);
}
else if (a[i].modvalue < nowmod)
{
//printf("ins %d %d %d\n", i, 1, a[i].modvalue);
//printf("ins %d %d %d\n", i, nowmod + 1, n);
if (a[i].modvalue >= && pre[a[i].modvalue] - pre[] != )
{
flag = ;
break;
}
if (n >= nowmod + && pre[n] - pre[nowmod] != )
{
flag = ;
break;
}
ins(root, , n, , a[i].modvalue, i);
ins(root, , n, nowmod + , n, i);
}
}
}
if (!flag)
{
cout << - << endl;
init(tot);
continue;
}
//cout << "!!!" << endl;
for (int i = ; i <= tot; i++)
{
if (i <= n)
{
nowvalue[i] = a[i].value;
}
else
{
nowvalue[i] = -;
}
}
// for (int i = 1; i <= tot; i++)
// {
// if (!visit[i])
// {
// get_du(i);
// }
// }
// for (int i = 1; i <= n; i++)
// {
// cout << "i du " << i << " " << du[i] << endl;
// }
for (int i = ; i <= tot; i++)
{
if (du[i] == )
{
//cout << "push " << nowvalue[i] << " " << i << endl;
q.push(make_pair(nowvalue[i], i));
}
}
//cout << "!!!" << endl;
pair<int, int> cnt;
while (!q.empty())
{
cnt = q.top();
q.pop();
if (cnt.first >= )
{
//cout << cnt.first << "zzzz" << endl;
finalans.push(cnt.first);
}
for (int v, i = Head[cnt.second]; i; i = nxt[i])
{
v = to[i];
//cout << i << " too " << v << " " << nowvalue[cnt.second] << " nowvalue " << nowvalue[v] << endl;
du[v]--;
if (du[v] == )
{
q.push(make_pair(nowvalue[v], v));
}
}
}
if (finalans.size() != sum)
{
printf("-1\n");
}
else
{
while (!finalans.empty())
{
printf("%d", finalans.front());
finalans.pop();
if (finalans.size() > )
{
putchar(' ');
}
else
{
putchar('\n');
}
}
}
init(tot);
}
}

uestc summer training #3 线段树优化建边的更多相关文章

  1. 【BZOJ4383】[POI2015]Pustynia 线段树优化建图

    [BZOJ4383][POI2015]Pustynia Description 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r ...

  2. AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图

    AtCoder Regular Contest 069 F Flags 二分,2-sat,线段树优化建图 链接 AtCoder 大意 在数轴上放上n个点,点i可能的位置有\(x_i\)或者\(y_i\ ...

  3. loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点

    loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点 链接 loj 思路 用交错关系建出图来,发现可以直接缩点,拓扑统计. 完了吗,不,瓶颈在于边数太多了,线段树优化建图. 细节 ...

  4. bzoj3073: [Pa2011]Journeys 线段树优化建图

    bzoj3073: [Pa2011]Journeys 链接 BZOJ 思路 区间和区间连边.如何线段树优化建图. 和单点连区间类似的,我们新建一个点,区间->新点->区间. 又转化成了单点 ...

  5. BZOJ 3073: [Pa2011]Journeys Dijkstra+线段树优化建图

    复习一下线段树优化建图:1.两颗线段树的叶子节点的编号是公用的. 2.每次连边是要建两个虚拟节点 $p1,p2$ 并在 $p1,p2$ 之间连边. #include <bits/stdc++.h ...

  6. bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4383 题解 暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系. 因为不存在零环 ...

  7. BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图

    Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...

  8. codeforces 787D - Legacy 线段树优化建图,最短路

    题意: 有n个点,q个询问, 每次询问有一种操作. 操作1:u→[l,r](即u到l,l+1,l+2,...,r距离均为w)的距离为w: 操作2:[l,r]→u的距离为w 操作3:u到v的距离为w 最 ...

  9. Codeforces 1045A Last chance 网络流,线段树,线段树优化建图

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045A.html 题目传送们 - CF1045A 题意 你有 $n$ 个炮,有 $m$ 个敌人,敌人排成一 ...

随机推荐

  1. 2019.06.05 ABAP EXCEL 操作类代码 OLE方式(模板下载,excel上传,内表下载)

    一般使用标准的excel导入方法9999行,修改了标准的excel导入FM 整合出类:excel的 模板下载,excel上传,ALV内表下载功能. 在项目一开始可以SE24创建一个类来供整体开发使用, ...

  2. Python web 项目的依赖管理工具

    Poetry可以帮助你声明.管理和安装Python项目的依赖项,确保你可以在任何地方都拥有正确的堆栈. Poetry支持Python 2.7 和Python 3以上 安装 Poetry提供了一个自定义 ...

  3. Java并发编程之程序运行堆栈分析

    Java程序运行的堆栈分析 1.JVM运行时数据区 JVM通过加载class文件的数据来执行程序.JVM在运行时会划分不同的区域以存放数据.如下图所示: 线程共享部分:所有线程都能访问这块内存的数据, ...

  4. PJzhang:shell基础入门的2个疗程-one

    猫宁!!! 在centos7上操作这一切 第1节:什么是shell centos7默认使用shell的bash cat /etc/shells 第2节:linux的启动过程 BIOS(主板,引导介质) ...

  5. PJzhang:python基础入门的7个疗程-three

    猫宁!!! 参考链接:易灵微课-21天轻松掌握零基础python入门必修课-售价29元人民币 https://www.liaoxuefeng.com/wiki/1016959663602400 第七天 ...

  6. git与gitlab工具

    1.Git和SVN的对比 1)git是分布式的,svn是集中式的.(最核心) 2)git是每个历史版本都存储完整的文件,便于恢复,svn是存储差异文件,历史版本不可恢复.(核心) 3)git可离线完成 ...

  7. Linux C/C++基础——变量作用域

    1.局部变量 局部变量也叫auto自动变量(auto可写可不写),一般情况下代码块{}内部定义的变量都是自动变量,它有如下特点: 只有当执行到这句语句时,系统才为这个变量分配空间 在一个函数内定义,只 ...

  8. 【Linux开发】linux设备驱动归纳总结(三):1.字符型设备之设备申请

    linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru 10.04 实验平台:S3C2440 + linux2.6.29内核 注:在今后驱动程序的学习中经常需要查看内核源代 ...

  9. python 爬虫 urllib模块 发起post请求

    urllib模块发起的POST请求 案例:爬取百度翻译的翻译结果 1.通过浏览器捉包工具,找到POST请求的url 针对ajax页面请求的所对应url获取,需要用到浏览器的捉包工具.查看百度翻译针对某 ...

  10. 树状数组+二维前缀和(A.The beautiful values of the palace)--The Preliminary Contest for ICPC Asia Nanjing 2019

    题意: 给你螺旋型的矩阵,告诉你那几个点有值,问你某一个矩阵区间的和是多少. 思路: 以后记住:二维前缀和sort+树状数组就行了!!!. #define IOS ios_base::sync_wit ...