uestc summer training #3 线段树优化建边

线段树建边

struct E
{
        int value, modvalue;
} a[MAXN << 3];
pair<int, int> b[MAXN];
int root, l[MAXN << 3], r[MAXN << 3], 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) >> 1;
        l[x] = build(a, mid);
        r[x] = build(mid + 1, 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) >> 1;
        if (c <= mid)
        {
                ins(l[x], a, mid, c, d, p);
        }
        if (d > mid)
        {
                ins(r[x], mid + 1, 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 = 1000010, M = 8000000;
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[2][N], nxt[2][M], v[2][M], ed, f[N], q[N], t, vis[N], ban[N];
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) >> 1;
        l[x] = build(a, mid);
        r[x] = build(mid + 1, 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) >> 1;
        if (c <= mid)
        {
                ins(l[x], a, mid, c, d, p);
        }
        if (d > mid)
        {
                ins(r[x], mid + 1, b, c, d, p);
        }
}
inline int askl(int x) //min >=x
{
        int l = 1, r = n, mid, t;
        while (l <= r)
        {
                mid = (l + r) >> 1;
                if (b[mid].first >= x)
                {
                        r = (t = mid) - 1;
                }
                else
                {
                        l = mid + 1;
                }
        }
        return t;
}
inline int askr(int x) //max <=x
{
        int l = 1, r = n, mid, t;
        while (l <= r)
        {
                mid = (l + r) >> 1;
                if (b[mid].first <= x)
                {
                        l = (t = mid) + 1;
                }
                else
                {
                        r = mid - 1;
                }
        }
        return t;
}
void dfs1(int x)
{
        vis[x] = 1;
        for (int i = g[0][x]; i; i = nxt[0][i])
                if (!vis[v[0][i]])
                {
                        dfs1(v[0][i]);
                }
        q[++t] = x;
}
void dfs2(int x, int y)
{
        vis[x] = 0;
        f[x] = y;
        for (int i = g[1][x]; i; i = nxt[1][i])
                if (vis[v[1][i]])
                {
                        dfs2(v[1][i], y);
                }
}
void dfs3(int x)
{
        if (ban[x])
        {
                return;
        }
        ban[x] = 1;
        for (int i = g[1][x]; i; i = nxt[1][i])
        {
                dfs3(v[1][i]);
        }
}
inline void solve(int x)
{
        if (vis[x])
        {
                return;
        }
        vis[x] = 1;
        for (int i = g[1][x]; i; i = nxt[1][i])
        {
                dfs3(v[1][i]);
        }
}
int main()
{
        scanf("%d%d", &n, &m);
        for (i = 1; 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 + 1, b + n + 1); //根据每个点的位置进行排序
        tot = n; //初始会有n个节点
        root = build(1, n);  //建立线段树并对线段树上的节点进行赋值
        for (i = 1; i <= n; i++)
        {
                int l = askl(a[i].p - a[i].r); //二分得到最左边炸到的节点
                int r = askr(a[i].p + a[i].r); //二分得到最右边炸到的节点
                ins(root, 1, n, l, r, i); //把该节点和线段树上范围为子区间的节点连一条边
        }
        for (t = 0, i = 1; i <= tot; i++)
                if (!vis[i])
                {
                        dfs1(i);
                }
        for (i = tot; i; i--)
                if (vis[q[i]])
                {
                        dfs2(q[i], q[i]);
                }
        ed = 0;  //ed为SCC的边总数
        for (i = 1; i <= tot; i++)  //SCC前向星初始化head数组
        {
                g[1][i] = 0;
        }
        for (i = 1; i <= tot; i++)
                for (j = g[0][i]; j; j = nxt[0][j])
                        if (f[i] != f[v[0][j]]) //不同SCC之间建边
                        {
                                ADD(f[i], f[v[0][j]]);
                        }
        for (i = 1; i <= n; i++)
        {
                solve(f[i]);
        }
        for (i = 1; i <= n; i++)
                if (!ban[f[i]]) //如果f[i]这个SCC是合法的话 就插入该点的一个值
                {
                        T[f[i]].insert(P(a[i].c, i));
                }
        for (i = 1; 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);
        }
}
View Code

自己写的:

/*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 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 5e5 + 5, MAXM = 3e6 + 5;
int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], ed = 1;
typedef pair<int, int> P;
const int N = 500010, M = 6000000;
int n, m, i, j, x, y;
long long ans;
struct E
{
        int p, r, c;
} a[N];
P b[N];
int to2[MAXM << 1], nxt2[MAXM << 1], Head2[MAXN];
int ed2 = 1;
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) >> 1;
        l[x] = build(a, mid);
        r[x] = build(mid + 1, 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) >> 1;
        if (c <= mid)
        {
                ins(l[x], a, mid, c, d, p);
        }
        if (d > mid)
        {
                ins(r[x], mid + 1, b, c, d, p);
        }
}
inline int askl(int x) //min >=x
{
        int l = 1, r = n, mid, t;
        while (l <= r)
        {
                mid = (l + r) >> 1;
                if (b[mid].first >= x)
                {
                        r = (t = mid) - 1;
                }
                else
                {
                        l = mid + 1;
                }
        }
        return t;
}
inline int askr(int x) //max <=x
{
        int l = 1, r = n, mid, t;
        while (l <= r)
        {
                mid = (l + r) >> 1;
                if (b[mid].first <= x)
                {
                        l = (t = mid) + 1;
                }
                else
                {
                        r = mid - 1;
                }
        }
        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 = 0;/*目前强连通分量的数目*/
int rudu[MAXN];
int ok[N];
queue<int> q, anser;
void tarjan(int x)
{
        dfn[x] = ++deep;
        low[x] = deep;
        visit[x] = 1;
        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] = 0;
                while (sta[top] != x)
                {
                        color[sta[top]] = colorsum;
                        visit[sta[top--]] = 0;
                }
                top--;
        }
}
inline void read(int &v)
{
        v = 0;
        char c = 0;
        int p = 1;
        while (c < '0' || c > '9')
        {
                if (c == '-')
                {
                        p = -1;
                }
                c = getchar();
        }
        while (c >= '0' && c <= '9')
        {
                v = (v << 3) + (v << 1) + c - '0';
                c = getchar();
        }
        v *= p;
}
int main()
{
        read(n), read(m);
        for (i = 1; i <= n; i++)
        {
                read(a[i].p), read(a[i].r), read(a[i].c);
                b[i] = P(a[i].p, i);
        }
        sort(b + 1, b + n + 1);
        tot = n;
        root = build(1, n);
        for (i = 1; i <= n; i++)
        {
                int l = askl(a[i].p - a[i].r);
                int r = askr(a[i].p + a[i].r);
                ins(root, 1, n, l, r, i);
        }
        for (int i = 1; i <= tot; i++)
        {
                if (i <= n)
                {
                        value[i] = a[i].c;
                }
                else
                {
                        value[i] = INT_MAX;
                }
        }
        for (int i = 1; i <= tot; i++)
        {
                if (!dfn[i])
                {
                        tarjan(i);
                }
        }
        for (int i = 1; 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 = 1; i <= colorsum; i++)
        {
                if (rudu[i] == 0)
                {
                        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] == 0)
                                {
                                        q.push(v);
                                }
                        }
                }
        }
        while (!anser.empty())
        {
                int now = anser.front();
                anser.pop();
                ans += valuemin[now].begin()->first;
                ok[now] = 1;
                //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;
        }
}
View Code

牛客第四场 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 + 7;
const int gakki = 5 + 2 + 1 + 19880611 + 1e9;
const int MAXN = 8e6 + 5, MAXM = 1e7 + 5;
int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], ed = 1;
typedef pair<int, int> P;
const int N = 1000010, M = 10000000;
int n, m, i, j, x, y;
long long ans;
struct E
{
        int value, modvalue;
} a[N];
P b[N];
int pre[N], flag = 1;
int number = 0;
int wait[N];
int root, l[N], r[N], tot;
queue<int> finalans;
bool visit[N];
int du[N];
int sum = 0;
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) >> 1;
        l[x] = build(a, mid);
        r[x] = build(mid + 1, 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) >> 1;
        if (c <= mid)
        {
                ins(l[x], a, mid, c, d, p);
        }
        if (d > mid)
        {
                ins(r[x], mid + 1, b, c, d, p);
        }
}
inline void read(int &v)
{
        v = 0;
        char c = 0;
        int p = 1;
        while (c < '0' || c > '9')
        {
                if (c == '-')
                {
                        p = -1;
                }
                c = getchar();
        }
        while (c >= '0' && c <= '9')
        {
                v = (v << 3) + (v << 1) + c - '0';
                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[0] = number = 0;
        sum = 0;
        flag = ed = 1;
        for (int i = 0; i <= x + 1; i++)
        {
                visit[i] = Head[i] = du[i] = 0;
        }
}
int main()
{
        int T;
        read(T);
        while (T--)
        {
                read(n);
                for (i = 1; i <= n; i++)
                {
                        pre[i] = pre[i - 1];
                        read(a[i].value);
                        if (a[i].value != -1)
                        {
                                sum++;
                        }
                        else
                        {
                                pre[i]++;
                        }
                        a[i].modvalue = i - 1;
                        b[i] = P(a[i].modvalue, i);
                }
                tot = n;
                if (sum == 0)
                {
                        cout << endl;
                        init(tot);
                        continue;
                }
                root = build(1, n);
                for (i = 1; i <= n; i++)
                {
                        if (a[i].value != -1)
                        {
                                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 + 1 && pre[a[i].modvalue] - pre[nowmod] != 0)
                                        {
                                                flag = 0;
                                                break;
                                        }
                                        ins(root, 1, n, nowmod + 1, 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 >= 1 && pre[a[i].modvalue] - pre[0] != 0)
                                        {
                                                flag = 0;
                                                break;
                                        }
                                        if (n >= nowmod + 1 && pre[n] - pre[nowmod] != 0)
                                        {
                                                flag = 0;
                                                break;
                                        }
                                        ins(root, 1, n, 1, a[i].modvalue, i);
                                        ins(root, 1, n, nowmod + 1, n, i);
                                }
                        }
                }
                if (!flag)
                {
                        cout << -1 << endl;
                        init(tot);
                        continue;
                }
                //cout << "!!!" << endl;
                for (int i = 1; i <= tot; i++)
                {
                        if (i <= n)
                        {
                                nowvalue[i] = a[i].value;
                        }
                        else
                        {
                                nowvalue[i] = -1;
                        }
                }
                //                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 = 1; i <= tot; i++)
                {
                        if (du[i] == 0)
                        {
                                //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 >= 0)
                        {
                                //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] == 0)
                                {
                                        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() > 0)
                                {
                                        putchar(' ');
                                }
                                else
                                {
                                        putchar('\n');
                                }
                        }
                }
                init(tot);
        }
}
View Code

 

posted @ 2018-07-18 21:55  Aragaki  阅读(191)  评论(0编辑  收藏  举报