线段树建边

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. [笔记] Ubuntu 18.04安装Docker CE及NVIDIA Container Toolkit流程

    之前写的[笔记] Ubuntu 18.04安装Docker CE及nvidia-docker2流程已经out了,以这篇为准. Docker的好处之一,就是在Container里面可以随意瞎搞,不用担心 ...

  2. MongoDB数据节点基础操作

    1.查看集群中各节点的状态: rs0:PRIMARY> rs.status() 2.查看集群中各节点配置情况: rs0:PRIMARY> rs.conf() 3.主节点降级为从节点: rs ...

  3. iOS10权限问题

    下图就是Info.plist的常用的权限问题: * 麦克风权限:Privacy - Microphone Usage Description 是否允许此App使用你的麦克风? * 相机权限: Priv ...

  4. B/S结构-登录页面-测试用例设计

    页面描述: 有一个登陆页面, 假如上面有2个textbox, 一个提交按钮 测试需求: 请针对这个页面设计30个以上的testcase 功能测试(Function test) 0. 什么都不输入,点击 ...

  5. asp.net之后台使用根目录运算符

    在asp.net前台,大家会经常使用根目录运算符~.这样,可以不用考虑网站的配置目录. 有时,需要在后台设置路径,同样需要使用根目录运算符.好吧,其实我每次需要使用这种方法,就需要在baidu上查找如 ...

  6. Servlet请求和响应

    在Java Web中Servlet.请求和响应是最基本的三个对象,在Web容器的管理下,这三者能够完成基本的HTTP请求处理. Servlet的作用是为客户提供服务.servlet的角色是接受一个客户 ...

  7. SqlServer中#和##的区别

    本地临时表的名称以单个数字字符(#)开头,它们仅对当前的用户连接是可见的. 全局临时表的名称以两个数字字符(##)开头,创建后对任何用户都是可见的.

  8. 比反射更快!使用ASM获取class信息(ClassReader)

    比反射更快!使用ASM获取class信息(ClassReader) 通常我们想要在java运行时获取class的信息时,通常使用反射的方式来获取其中的属性,方法,注解等信息.通常是这样的: Class ...

  9. PHPstorm支持YAF框架代码自动提示

    文件下载地址:https://github.com/xudianyang/yaf.auto.complete 然后找到phpstorm     File->settings->Langua ...

  10. redis配置文档细节问题

    在window10环境下,redis的.conf配置文件在使用时,不可以有多余的空白符.比如为了对其在配置的前方添加两个空格. 这么做会导致redis-server使用这个配置文件的时候无法正常启动, ...