(4.17~4.23)

[POJ 3417] Network

LCA + 树上差分

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5+50;
typedef long long ll;
///加边
int cnt, h[maxn];
struct edge
{
    int to, pre, v;
} e[maxn << 1];
void init()
{
    cnt = 0;
    memset(h, 0, sizeof(h));
}
void add(int from, int to, int v)
{
    cnt++;
    e[cnt].pre = h[from]; ///5-->3-->1-->0
    e[cnt].to = to;
    e[cnt].v = v;
    h[from] = cnt;
}
///LCA
int dist[maxn];
int dep[maxn];
int anc[maxn][33]; ///2分的父亲节点
void dfs(int u, int fa)
{
    for(int i = h[u]; i; i = e[i].pre)
    {
        int v = e[i].to;
        if(v == fa) continue;
        dist[v] = dist[u] + e[i].v;
        dep[v] = dep[u] + 1;
        anc[v][0] = u;
        dfs(v, u);
    }
}
void LCA_init(int n)
{
    for(int j = 1; (1 << j) < n; j++)
        for(int i = 1; i <= n; i++) if(anc[i][j-1])
        anc[i][j] = anc[anc[i][j-1]][j-1];
}
int LCA(int u, int v)
{
    int log;
    if(dep[u] < dep[v]) swap(u, v);
    for(log = 0; (1 << log) < dep[u]; log++);
    for(int i = log; i >= 0; i--)
        if(dep[u] - (1 << i) >= dep[v]) u = anc[u][i];
    if(u == v) return u;
    for(int i = log; i >= 0; i--)
        if(anc[u][i] && anc[u][i] != anc[v][i])
            u = anc[u][i], v = anc[v][i];
    return anc[u][0];
}
int w[maxn];
int sum[maxn];
int dfs2(int u, int fa)
{
    sum[u] += w[u];
    for(int i = h[u]; i; i = e[i].pre)
    {
        int v = e[i].to;
        if(v == fa) continue;
        sum[u] += dfs2(v, u);
    }
    return sum[u];
}
int main()
{
    init();
    int n, m; scanf("%d %d", &n, &m);
    for(int i = 1; i < n; i++)
    {
        int u, v; scanf("%d %d", &u, &v);
        add(u, v, 1), add(v, u, 1);
    }
    dfs(1, -1);
    LCA_init(n);
    memset(w, 0, sizeof(w));
    for(int i = 1; i <= m; i++)
    {
        int u, v; scanf("%d %d", &u ,&v);
        w[u] += 1, w[v] += 1;
       // printf("%d
", LCA(u, v));
        w[LCA(u, v)] += -2;
    }
    dfs2(1, -1);
    /*for(int i = 1; i <= n; i++)
    {
        printf("%d
", sum[i]);
    }*/
    int ans = 0;
    for(int i = 2; i <= n; i++)
    {
        if(sum[i] == 0) ans += m;
        if(sum[i] == 1) ans++;
    }
    printf("%d
", ans);
    return 0;
}
Code

Destruction of a Tree

各种剪枝。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 50;
vector<int> g[maxn];
int in[maxn];
int vis[maxn];
vector<int> ans;
void dfs(int u, int fa, int flag)
{
    if(flag == 0)
    {
        for(int i = 0; i < g[u].size(); i++)
        {
            int v = g[u][i];
            if(v == fa) continue;
            dfs(v, u, 0);
        }
    }
    if(in[u] != 0 && (in[u] % 2 == 0))
    {
        if(!vis[u]) ans.push_back(u), vis[u] = 1;
        for(int i = 0; i < g[u].size(); i++)
        {
            int v = g[u][i];
            if(flag == 1 && v == fa) continue;


            if(in[u] > 0)in[u]--;
            if(in[v] > 0)
            {
                in[v]--;
                if(in[v] == 0 && (!vis[v])) ans.push_back(v), vis[v] = 1;
            }
            if(v == fa) continue;
            if(in[v] != 0 && (in[v] % 2 == 0)) dfs(v, u, 1);
        }
    }
}
int main()
{
    int n; scanf("%d", &n);
    int fa = 0;
    memset(in, 0, sizeof(in));
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n; i++)
    {
        int x; scanf("%d", &x);
        if(!x) fa = i;
        else g[x].push_back(i), g[i].push_back(x), in[i]++, in[x]++;
    }
    dfs(fa, -1, 0);
    int cnt = 0;
    for(int i = 1; i <= n; i++) if(in[i] == 0) cnt++;
    if(cnt == n)
    {
        printf("YES
");
        for(int i = 0; i < ans.size(); i++) printf("%d
", ans[i]);
        if(n == 1) printf("1
");
    }
    else printf("NO
");

    return 0;
}
Code

BZOJ 4195

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 50;
int pre[maxn * 2];
int x[maxn * 2];
struct node
{
    int l, r, w;
    friend bool operator < (node A, node B)
    {
        if(A.w != B.w)return A.w > B.w;
        else return A.l < B.l;
    }
};
node cnt[maxn];
int Find(int x)
{
    return x == pre[x] ? x : pre[x] = Find(pre[x]);
}
void merge1(int x,int y)
{
    pre[Find(x)] = Find(y);
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        for(int i = 0; i < maxn * 2; i++) pre[i] = i;
        int num = 0;
        int n; scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d %d", &cnt[i].l, &cnt[i].r, &cnt[i].w);
            x[num++] = cnt[i].l, x[num++] = cnt[i].r;
        }
        sort(x, x + num);
        num = unique(x, x + num) - x;
        for(int i = 1; i <= n; i++)
        {
            cnt[i].l = lower_bound(x, x + num, cnt[i].l) - x;
            cnt[i].r = lower_bound(x, x + num, cnt[i].r) - x;
        }
        sort(cnt + 1, cnt + n + 1);
        int flag = 0;
        for(int i = 1; i <= n; i++)
        {
            if(cnt[i].w)
            {
                merge1(cnt[i].l, cnt[i].r);
            }
            else
            {
                if(Find(cnt[i].l) == Find(cnt[i].r))
                {
                    flag = 1;
                    break;
                }
            }
        }
        if(flag) printf("NO
");
        else printf("YES
");
    }
    return 0;
}
/*
2
3
1 2 0
2 3 0
1 3 1
*/
Code

 POJ 1456

优先队列

#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
priority_queue <int, vector<int>, greater<int> > q;
const int maxn = 1e4 + 50;
vector<int> pro[maxn];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i < maxn; i++) pro[i].clear();
        int p, d;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d", &p, &d);
            pro[d].push_back(p);
        }
        for(int i = 1; i <= 10000; i++) sort(pro[i].begin(), pro[i].end());
        for(int i = 1; i <= 10000; i++)
        {
            int tmp = i;
            for(int j = pro[i].size() - 1; j >= 0 && tmp >= 1; j--, tmp--)
            {
                 q.push(pro[i][j]);
            }
            while(q.size() > i) q.pop();
        }
        int sum = 0;
        while(!q.empty())
        {
            sum += q.top();
            q.pop();
        }
        printf("%d
", sum);
    }
    return 0;
}
/*
2
3
1 2 0
2 3 0
1 3 1
*/
Code

贪心 + 并查集

#include <bits/stdc++.h>
using namespace std;
struct node
{
    int p, d;
    friend bool operator < (node A, node B)
    {
        return A.p > B.p;
    }
};
const int maxn = 1e4 + 50;
node cnt[maxn];
int pre[maxn];
int Find(int x)
{
    return x == pre[x] ? x : pre[x] = Find(pre[x]);
}
void merge1(int x, int y)
{
    pre[Find(x)] = Find(y);
}
int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i <= 10000; i++) pre[i] = i;
        for(int i = 1; i <= n; i++) scanf("%d %d", &cnt[i].p, &cnt[i].d);
        sort(cnt + 1, cnt + n + 1);
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int fa = Find(cnt[i].d);
            if(fa > 0) ans += cnt[i].p, pre[fa] = fa - 1;
        }
        printf("%d
", ans);
    }
    return 0;
}
Code

 CODEVS 1540

边带权并查集

晚上睡觉的时候想,如果 2 --> 3,这样的链接在 4 后面,这样d[2] = 2, d[3] = 1, d[4]  = 0,如果反复查询2的话,会变成不断累加? 答案是不会的,因为2 -- > 4。d数组要全部初始化成0

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int maxn  = 1e5;
int pre[maxn * 2];
struct node
{
    int l, r, st;
};
node cur[maxn];
int x[maxn * 2];
int d[maxn * 2];
int Find(int x)
{
    if(x == pre[x]) return x;
    int root = Find(pre[x]);
    d[x] ^= d[pre[x]];
    return pre[x] = root;
}
int main()
{
    int len, n;
    scanf("%d %d", &len, &n);
    int m = 0;
    memset(d, 0, sizeof(d));
    for(int i = 1; i <= n; i++)
    {
        char s[10];
        scanf("%d %d %s", &cur[i].l, &cur[i].r, s);
        cur[i].st = (s[0] == 'e' ? 0 : 1);
      //  printf("%d
", cur[i].st);
        x[m++] = cur[i].l - 1;
        x[m++] = cur[i].r;
    }
    sort(x, x + m);
    m = unique(x, x + m) - x;
    for(int i = 0; i <= m; i++) pre[i] = i;
    for(int i = 1; i <= n; i++)
    {
        cur[i].l = lower_bound(x, x + m, cur[i].l - 1) - x;
        cur[i].r = lower_bound(x, x + m, cur[i].r) - x;
        int p = Find(cur[i].l);
        int q = Find(cur[i].r);
        if(p == q)
        {
        //    printf("dasda
");
            if((d[cur[i].l] ^ d[cur[i].r]) == cur[i].st) continue;
            printf("%d
", i - 1);
            return 0;
        }
        else pre[p] = q, d[p] = d[cur[i].l] ^ d[cur[i].r] ^ cur[i].st;
    }
    printf("%d
", n);
    return 0;
}
/*
10
4
2 5 even
6 8 odd
3 7 odd
2 8 even
*/
Code

 POJ 1733 

边带权并查集:

要能看出它的传递性:

sum[l,r]表示l,r之间1的个数

如果sum[l,r]为奇数,那么sum[r]与sum[l-1]奇偶性不同;

如果sum[l,r]为偶数,那么sum[r]与sum[l-1]奇偶性相同。

借助传递性,比如sum[2,5] 是 even, sum[1]与sum[5]相同,sum[6,8]是odd,sum[5]与sum[8]不同,所以sum[1]与sum[8]不同。

#include <bits/stdc++.h>
using namespace std;
const int maxn  = 1e4 + 50;
int pre[maxn * 2];
struct node
{
    int l, r, st;
};
node cur[maxn];
int x[maxn * 2];
int d[maxn * 2];
int Find(int x)
{
    if(x == pre[x]) return x;
    int root = Find(pre[x]);
    d[x] ^= d[pre[x]];
    return pre[x] = root;
}
int main()
{
    int len, n;
    scanf("%d %d", &len, &n);
    int m = 0;
    for(int i = 1; i <= n; i++)
    {
        char s[10];
        scanf("%d %d %s", &cur[i].l, &cur[i].r, s);
        cur[i].st = (s[0] == 'e' ? 0 : 1);
      //  printf("%d
", cur[i].st);
        x[m++] = cur[i].l;
        x[m++] = cur[i].r;
    }
    sort(x, x + m);
    m = unique(x, x + m) - x;
    for(int i = 0; i <= m; i++) pre[i] = i;
    for(int i = 1; i <= n; i++)
    {
        cur[i].l = lower_bound(x, x + m, cur[i].l) - x;
        cur[i].r = lower_bound(x, x + m, cur[i].r) - x;
        int p = Find(cur[i].l - 1);
        int q = Find(cur[i].r);
        if(p == q)
        {
        //    printf("dasda
");
            if((d[cur[i].l - 1] ^ d[cur[i].r]) == cur[i].st) continue;
            printf("%d
", i - 1);
            return 0;
        }
        else pre[p] = q, d[p] = d[cur[i].l - 1] ^ d[cur[i].r] ^ cur[i].st;
    }
    printf("%d
", n);
    return 0;
}
/*
10
4
2 5 even
6 8 odd
3 7 odd
2 8 even
*/
Code

 Mahmoud and a Dictionary

和上题一样。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 50;
map<string, int> mp;
int pre[maxn];
int d[maxn];
int Find(int x)
{
    if(x == pre[x]) return x;
    int root = Find(pre[x]);
    d[x] ^= d[pre[x]];
    return pre[x] = root;
}
int main()
{
    int n, m, q; scanf("%d %d %d", &n, &m, &q);
    char s[25];
    string tmp;
    for(int i = 1; i <= n; i++) scanf("%s", s), tmp = s, mp[s] = i, pre[i] = i, d[i] = 0;
    for(int i = 1; i <= m; i++)
    {
        int t;
        char s1[25], s2[25];
        scanf("%d %s %s", &t, s1, s2);
        int x = mp[s1], y = mp[s2];
        int ans = t == 1 ? 0 : 1;
        int p = Find(x);
        int q = Find(y);
        if(p == q)
        {
            if((d[x] ^ d[y]) == ans) printf("YES
");
            else printf("NO
");
        }
        else
        {
            pre[p] = q;
            d[p] = d[x] ^ d[y] ^ ans;
            printf("YES
");
        }
    }
    for(int i = 1; i <= q; i++)
    {
        char s1[25], s2[25];
        scanf("%s %s", s1, s2);
        int x = mp[s1], y = mp[s2];
        int p = Find(x);
        int q = Find(y);
        if(p != q) printf("3
");
        else
        {
            printf("%d
", (d[x] ^ d[y]) == 1 ? 2 : 1);
        }
    }
    return 0;
}
Code

 今天打完ningxia,听他们说最近有三道差不多的FFT,我看了三道题,然后看了两个题解,还是不太懂为啥那样做,我还是先把之前的FFT补补吧。

 

 

原文地址:https://www.cnblogs.com/littlepear/p/8867452.html