线段树建边

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. tcpdump分析tcp连接的建立、传输和关闭

    http://note.youdao.com/noteshare?id=2aa0379d1e4b3bcddc26174861ffe09a

  2. SqlServer:SqlServer(sql,游标,定时作业,行转列,列转行,公用表达式递归,merge合并)

    1.加载驱动: Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); DriverManager.getCo ...

  3. java:面向对象(多态,final,抽象方法,(简单工厂模式即静态方法模式),接口)

    * 生活中的多态:同一种物质,因环境不同而表现不同的形态. * 程序中多态:同一个"接口",因不同的实现而执行不同的操作. * 多态和方法的重写经常结合使用,子类重写父类的方法,将 ...

  4. ubuntu安装dockers过程:

    1. 先对系统进行更新 1.1 apt-get upgrade 1.2 去中国关于dockers的网站 http://get.daocloud.io/ 1.3 安装docker curl -sSL h ...

  5. 04 npm 命令大全

    一.npm简介   npm(Node Package Manager)是随同node.js 一起安装的包管理工具,为了解决nodejs代码部署上的很多问题,常用以下场景: 允许用户从npm服务器下载别 ...

  6. numpy的divide函数

    和直接用/一样,都是矩阵的对应元素相除. 如果用*,那么是矩阵的对应元素相乘. 如果要实现矩阵乘法,用numpy的dot函数.

  7. Pytorch1.0入门实战三:ResNet实现cifar-10分类,利用visdom可视化训练过程

    人的理想志向往往和他的能力成正比. —— 约翰逊 最近一直在使用pytorch深度学习框架,很想用pytorch搞点事情出来,但是框架中一些基本的原理得懂!本次,利用pytorch实现ResNet神经 ...

  8. staticmethod自己定制

    class StaticMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #类来调 ...

  9. C++面试题整理(持续更新中)

    一. 内联函数和宏定义的区别 1.内联函数在运行时可调试,而宏定义不可以: 2.编译器会对内联函数的参数类型做安全检查或自动类型转换(同普通类型),而宏定义不会: 3.内联函数可以访问类的成员变量,而 ...

  10. 【Python】【demo实验2】【打印乘法口诀表】

    打印乘法口诀表 源代码: # encoding=utf-8 for i in range(1,10): print("\n") for j in range(1,10): if i ...