Kuangbin专题五并查集

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40379678/article/details/81630336

并查集也是很难的啊。。。

A - Wireless Network

 POJ - 2236

An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B. 

In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations. 

Input

The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats: 
1. "O p" (1 <= p <= N), which means repairing computer p. 
2. "S p q" (1 <= p, q <= N), which means testing whether computer p and q can communicate. 

The input will not exceed 300000 lines. 

Output

For each Testing operation, print "SUCCESS" if the two computers can communicate, or "FAIL" if not.

Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4

Sample Output

FAIL
SUCCESS

几乎是板子题,修复一台电脑就连接,预处理出所有的距离小于d的点。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 1010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n;
double d;
P point[N];
double dist(const P & a, const P & b) {
    return sqrt((a.fi - b.fi) * (a.fi - b.fi) + (a.se - b.se) * (a.se - b.se));
}

int F[N];
bool vis[N];
vector<int> G[N];
void init()
{
    rep(i, 1, N - 1) G[i].clear();
    memset(vis, false, sizeof vis);
    memset(F, -1, sizeof F);
}
int find(int x)
{//cout << x <<' ' <<F[x]<<endl;
    if(-1 == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    x = find(x); y = find(y);
    if(x == y) return;
    F[x] = y;
}
bool same(int x, int y) {
    return find(x) == find(y);
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d%lf", &n, &d)) {
        rep(i, 1, n) scanf("%lf%lf", &point[i].fi, &point[i].se);
        init();

        rep(i, 1, n) rep(j, 1, n) {
            if(dist(point[i], point[j]) <= d) {
                G[i].push_back(j);
            }
        }

        char ch;
        int a, b;
        while(cin >> ch) {
            if(ch == 'O') {
                scanf("%d", &a);//cout << a <<endl;
                vis[a] = true;
                for(int i = 0; i < G[a].size(); i++) {
                    if(vis[G[a][i]]) unite(a, G[a][i]);
                }

            }
            else {
                scanf("%d%d", &a, &b);
                printf(same(a, b)?"SUCCESS\n":"FAIL\n");
            }
        }
    }

    return 0;
}


B - The Suspects

 POJ - 1611

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. 
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP). 
Once a member in a group is a suspect, all members in the group are suspects. 
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.

Input

The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space. 
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.

Output

For each case, output the number of suspects in one line.

Sample Input

100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

Sample Output

4
1
1

和0连着的就是嫌疑人了。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 30010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N];
void init(){
    memset(F, -1, sizeof F);
}
int find(int x)
{
    if(-1 == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    x = find(x); y = find(y);
    if(x == y) return;
    F[x] = y;
}
bool same(int x, int y) {
    return find(x) == find(y);
}

int n, m, k, a, b, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d%d", &n, &m) && n + m) {
        init();

        rep(i, 1, m) {
            scanf("%d", &k);
            if(k) scanf("%d", &a);
            rep(i, 1, k - 1) {
                scanf("%d", &b);
                unite(a, b);
            }
        }
        cnt = 1;
        rep(i, 1, n - 1) {
            if(same(0, i)) cnt++;
        }

        printf("%d\n", cnt);
    }

    return 0;
}



C - How Many Tables

 HDU - 1213

Today is Ignatius' birthday. He invites a lot of friends. Now it's dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers. 

One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table. 

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least. 

Input

The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.

Output

For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks. 

Sample Input

2
5 3
1 2
2 3
4 5

5 1
2 5

Sample Output

2
4

数连通块的数量,数根就ok。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 30010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N];
void init(){
    memset(F, -1, sizeof F);
}
int find(int x)
{
    if(-1 == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    x = find(x); y = find(y);
    if(x == y) return;
    F[x] = y;
}
bool same(int x, int y) {
    return find(x) == find(y);
}

int n, m, t, a, b, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        init();

        rep(i, 1, m) {
            scanf("%d%d", &a, &b);
            unite(a, b);
        }

        cnt = 0;
        rep(i, 1, n) if(F[i] == -1) cnt++;

        printf("%d\n", cnt);
    }

    return 0;
}

D - How Many Answers Are Wrong

 HDU - 3038

TT and FF are ... friends. Uh... very very good friends -________-b 

FF is a bad boy, he is always wooing TT to play the following game with him. This is a very humdrum game. To begin with, TT should write down a sequence of integers-_-!!(bored). 


Then, FF can choose a continuous subsequence from it(for example the subsequence from the third to the fifth integer inclusively). After that, FF will ask TT what the sum of the subsequence he chose is. The next, TT will answer FF's question. Then, FF can redo this process. In the end, FF must work out the entire sequence of integers. 

Boring~~Boring~~a very very boring game!!! TT doesn't want to play with FF at all. To punish FF, she often tells FF the wrong answers on purpose. 

The bad boy is not a fool man. FF detects some answers are incompatible. Of course, these contradictions make it difficult to calculate the sequence. 

However, TT is a nice and lovely girl. She doesn't have the heart to be hard on FF. To save time, she guarantees that the answers are all right if there is no logical mistakes indeed. 

What's more, if FF finds an answer to be wrong, he will ignore it when judging next answers. 

But there will be so many questions that poor FF can't make sure whether the current answer is right or wrong in a moment. So he decides to write a program to help him with this matter. The program will receive a series of questions from FF together with the answers FF has received from TT. The aim of this program is to find how many answers are wrong. Only by ignoring the wrong answers can FF work out the entire sequence of integers. Poor FF has no time to do this job. And now he is asking for your help~(Why asking trouble for himself~~Bad boy) 

Input

Line 1: Two integers, N and M (1 <= N <= 200000, 1 <= M <= 40000). Means TT wrote N integers and FF asked her M questions. 

Line 2..M+1: Line i+1 contains three integer: Ai, Bi and Si. Means TT answered FF that the sum from Ai to Bi is Si. It's guaranteed that 0 < Ai <= Bi <= N. 

You can assume that any sum of subsequence is fit in 32-bit integer. 

Output

A single line with a integer denotes how many answers are wrong.

Sample Input

10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1

Sample Output

1

这种区间上一段一段信息差点让我以为是线段树,但是线段树操作有很多不方便,比如建树必须加标记,还要判断信息是否错误什么的。。。并查集的话把左边界减一或者右边界加一(套路是左边减一)来把个区间连起来(左开右闭),并查集的值是自己到老爸的区间的值,老爸在左在右是不影响操作的,路径压缩和合并会自动的调整数值正负号。

判断错就是当前区间由以前的信息已经可以确定的值的范围和给定的值矛盾。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 200010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, m, a, b, c, cnt;
int F[N], v[N];
void init()
{
    memset(v, 0, sizeof v);
    rep(i, 0, n) F[i] = i;
}
int find(int x)
{
    if(F[x] != x) {
        int tmp = F[x];
        F[x] = find(F[x]);
        v[x] += v[tmp];
    }
    return F[x];
}
bool unite(int x, int y, int sum)
{
    int a = find(x), b = find(y);
    if(a == b) return abs(v[y] - v[x]) == sum;
    F[b] = a;
    v[b] = v[x] + sum - v[y];
    return true;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d%d", &n, &m)) {
        init();
        cnt = 0;
        rep(i, 1, m) {
            scanf("%d%d%d", &a, &b, &c);
            if(!unite(a - 1, b, c)) cnt++;
           // if(!unite(a, b + 1, c)) cnt++;
        }
        printf("%d\n", cnt);
    }

    return 0;
}

E - 食物链

 POJ - 1182

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述: 
第一种说法是"1 X Y",表示X和Y是同类。 
第二种说法是"2 X Y",表示X吃Y。 
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
1) 当前的话与前面的某些真的话冲突,就是假话; 
2) 当前的话中X或Y比N大,就是假话; 
3) 当前的话表示X吃X,就是假话。 
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

Input

第一行是两个整数N和K,以一个空格分隔。 
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
若D=1,则表示X和Y是同类。 
若D=2,则表示X吃Y。

Output

只有一个整数,表示假话的数目。

Sample Input

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample Output

3

首先是不能多组输入,有点坑。

老题目了,以前看刘汝佳一直用的分两个不同段的并查集那种方法写的,现在知道了还能用向量存和父节点的关系写。

第一种写法是开一个三倍长的并查集,如果A吃B就同时维护A是第一类B是第二类、A是第二类B是第三类、A是第三类B是第一类三个信息,这样A就吃定B了,以后要是出现B吃A只需要查找一对就行了,不需要查找所有对的关系。

本来我第一遍写是这么查找的:


 if(same(a, b) || same(a + n, b + n) || same(a + 2 * n, b + 2 * n) || same(b, a + n) || same(b + n, a + 2 * n) || same(b + 2 * n, a))
                        cnt++;
 if(same(a, b + n) || same(a + n, b + 2 * n) || same(a + 2 * n, b) || same(b, a + n) || same(b + n, a + 2 * n) || same(b + 2 * n, a))
                   cnt++;

然后看以前的代码发现这么找就行:

if(same(a, b) || same(a, b + 2 * n))
      cnt++;
if(same(a, b + n) || same(a, b + n * 2))
      cnt++;
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 50010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int father[N * 3];
int rak[N * 3];

void init(int n)
{
    for(int i = 0; i <= n; i++){
        father[i] = i;
        rak[i] = 0;
    }
}

int find(int n)
{
    if(n == father[n])
        return n;
    else
        return father[n] = find(father[n]);
}

void unite(int x, int y)
{
    x = find(x);
    y = find(y);

    if(x == y)
        return;

    if(rak[x] < rak[y])
        father[x] = y;
    else{
        father[y] = x;
        if(rak[x] == rak[y])
            rak[x]++;
    }
}

bool same(int x, int y)
{
    return find(x) == find(y);
}
int n, k, d, a, b, c, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    scanf("%d%d", &n, &k);
    init(n * 3 + 1); cnt = 0;
    rep(i, 1, k) {
        scanf("%d%d%d", &d, &a, &b);
            if(a > n || b > n || a <= 0 || b <= 0) cnt++;
            else if(d == 2) {
                if(same(a, b) || same(a, b + 2 * n))
                    cnt++;
                else {
                    unite(a, b + n);
                    unite(a + n, b + n * 2);
                    unite(a + n * 2, b);
                }
            }
            else {
                if(same(a, b + n) || same(a, b + n * 2))
                    cnt++;
                else {
                    unite(a, b);
                    unite(a + n, b + n);
                    unite(a + n * 2, b + n * 2);
                }
            }
        }
        printf("%d\n", cnt);


    return 0;
}

第二种是偏移量法,i->j表示i吃j,j->k表示j吃k,i<-k表示k吃i,那么i->j->k应该也是k吃i,给->赋值为1,那么i->j->k就是2,表示k吃i,所以<-赋值为2,于是关系的转移就成了mod3的加法。可以用穷举法证明。

合并时,已知x到y是d,x到rx是R[x],y到ry是R[y],所以rx到ry用向量传递就是rx->x->y->ry,也就是-R[x]+d+R[y]。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 50010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N], R[N];
void init(){
    rep(i, 0, N - 1) F[i] = i;
    memset(R, 0, sizeof R);
}
int find(int x)
{
    if(F[x] != x) {
        int fa = F[x];
        F[x] = find(F[x]);
        R[x] = (R[x] + R[fa]) % 3;
    }
    return F[x];
}
bool unite(int x, int y, int d)
{
    int rx = find(x), ry = find(y);
    //cout << x <<' ' <<rx<<' ' <<y <<' ' <<ry<<' ' <<R[x]<<' ' <<R[y]<<endl;
    if(rx == ry) {
        return d == ((3 + R[x] - R[y]) % 3);
    }

    F[rx] = ry;
    R[rx] = (R[y] - R[x] + d + 3) % 3;
    return true;
}

int n, k, d, x, y, cnt;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    scanf("%d%d", &n, &k);
    init();
    cnt = 0;
    rep(i, 1, k) {
        scanf("%d%d%d", &d, &x, &y);
       // cout <<cnt <<endl;
        if(x <= 0 || x > n || y <= 0 || y > n) {
            cnt++; continue;
        }
        if(!unite(x, y, d - 1)) {
            cnt++; continue;
        }
    }
    printf("%d\n", cnt);

    return 0;
}

F - True Liars

 POJ - 1417

After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally cast ashore on a foggy island. Though he was exhausted and despaired, he was still fortunate to remember a legend of the foggy island, which he had heard from patriarchs in his childhood. This must be the island in the legend. In the legend, two tribes have inhabited the island, one is divine and the other is devilish, once members of the divine tribe bless you, your future is bright and promising, and your soul will eventually go to Heaven, in contrast, once members of the devilish tribe curse you, your future is bleak and hopeless, and your soul will eventually fall down to Hell. 

In order to prevent the worst-case scenario, Akira should distinguish the devilish from the divine. But how? They looked exactly alike and he could not distinguish one from the other solely by their appearances. He still had his last hope, however. The members of the divine tribe are truth-tellers, that is, they always tell the truth and those of the devilish tribe are liars, that is, they always tell a lie. 

He asked some of them whether or not some are divine. They knew one another very much and always responded to him "faithfully" according to their individual natures (i.e., they always tell the truth or always a lie). He did not dare to ask any other forms of questions, since the legend says that a devilish member would curse a person forever when he did not like the question. He had another piece of useful informationf the legend tells the populations of both tribes. These numbers in the legend are trustworthy since everyone living on this island is immortal and none have ever been born at least these millennia. 

You are a good computer programmer and so requested to help Akira by writing a program that classifies the inhabitants according to their answers to his inquiries.

Input

The input consists of multiple data sets, each in the following format : 

n p1 p2 
xl yl a1 
x2 y2 a2 
... 
xi yi ai 
... 
xn yn an 

The first line has three non-negative integers n, p1, and p2. n is the number of questions Akira asked. pl and p2 are the populations of the divine and devilish tribes, respectively, in the legend. Each of the following n lines has two integers xi, yi and one word ai. xi and yi are the identification numbers of inhabitants, each of which is between 1 and p1 + p2, inclusive. ai is either yes, if the inhabitant xi said that the inhabitant yi was a member of the divine tribe, or no, otherwise. Note that xi and yi can be the same number since "are you a member of the divine tribe?" is a valid question. Note also that two lines may have the same x's and y's since Akira was very upset and might have asked the same question to the same one more than once. 

You may assume that n is less than 1000 and that p1 and p2 are less than 300. A line with three zeros, i.e., 0 0 0, represents the end of the input. You can assume that each data set is consistent and no contradictory answers are included. 
 

Output

For each data set, if it includes sufficient information to classify all the inhabitants, print the identification numbers of all the divine ones in ascending order, one in a line. In addition, following the output numbers, print end in a line. Otherwise, i.e., if a given data set does not include sufficient information to identify all the divine members, print no in a line.

Sample Input

2 1 1
1 2 no
2 1 no
3 2 1
1 1 yes
2 2 yes
3 3 yes
2 2 1
1 2 yes
2 3 no
5 4 3
1 2 yes
1 3 no
4 5 yes
5 6 yes
6 7 no
0 0 0

Sample Output

no
no
1
2
end
3
4
5
6
end

https://blog.csdn.net/acm_cxlove/article/details/8092799

好难的题。。。。。。

并查集部分难度倒不大,每个块跟根节点比较就能分两色,求数量问题也不大,我死在背包上了Orz。不死也吓死了。Orz。根本就没有背包的意识Orz。然后输出路径好像刘汝佳上有写过,完全不记得了Orz。动规要输出路径不能滚动数组。

if(j - a[i][0] >= 0) dp[i][j] += dp[i - 1][j - a[i][0]];
if(j - a[i][1] >= 0) dp[i][j] += dp[i - 1][j - a[i][1]];

关于这个动规的状态转移方程,如果a[i][0]和a[i][1]都不同那么转移过来没啥,如果相同那么说明第i堆亦正亦邪随你便,那么就不能确定,那么d[i][j]就大于二,说拜拜。

路径的推导是从后往前推,找到每个层次的最优解。也可以在状态转移的过程中就记录下0还是1。然后虽然路径肯定是唯一的(不唯一dp值就大于一了),但是推导路径的for循环里else不能少,第一个if会改变p1p2的值。。。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 610
#define M 20010
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N], R[N];
int p1, p2, p;
bool vis[N];
int dp[N][N / 2];
int cnt;
int a[N][2];
int u, v;
char str[5];
vector<int> b[N][2], ans;

void init()
{
    rep(i, 0, p1 + p2) F[i] = i, R[i] = 0;
    memset(vis, false, sizeof vis);
    cnt = 1;
    memset(a, 0, sizeof a);
    rep(i, 0, N - 1) {
        b[i][0].clear();
        b[i][1].clear();
    }
}

int find(int x)
{
    if(x != F[x]) {
        int fa = F[x];
        F[x] = find(F[x]);
        R[x] = R[x] ^ R[fa];
    }
    return F[x];
}
void unite(int u, int v, bool k)
{
    int ru = find(u), rv = find(v);
    if(ru != rv) {
        F[ru] = rv;
        R[ru] = R[u] ^ R[v] ^ k;
        //cout << "r " <<R[ru] <<endl;
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(scanf("%d%d%d", &p, &p1, &p2) && p + p1 + p2) {
        init();

        while(p--) {
            scanf("%d%d%s", &u, &v, str);
            unite(u, v, str[0] == 'n');
        }

        rep(i, 1, p1 + p2) if(!vis[i]) {
            int fa = find(i);
            rep(j, i, p1 + p2) if(find(j) == fa) {
                vis[j] = true;
                b[cnt][R[j]].push_back(j);
                a[cnt][R[j]]++;
              //  cout << "j " <<j <<endl;
            }
            cnt++;
        }
//rep(i, 1,  cnt - 1) cout << a[i][0] << ' '<<a[i][1] <<endl;
//cout <<"cnt " <<b[cnt - 1][0].size() <<endl;
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        rep(i, 1, cnt - 1) {
            for(int j = p1; j >= 0; j--) {
                if(j - a[i][0] >= 0) dp[i][j] += dp[i - 1][j - a[i][0]];
                if(j - a[i][1] >= 0) dp[i][j] += dp[i - 1][j - a[i][1]];
            }
        }
//    rep(i, 1, cnt - 1) {
//        rep(j, 0, p1) cout << dp[i][j] << ' ';
//        cout <<endl;
//    }
        if(dp[cnt - 1][p1] != 1) puts("no");
        else {
            ans.clear();
//cout <<"a\n";
            for(int i = cnt - 1; i >= 1; i--) {
              //  int tmp1 = p1, tmp2 = p2;
                if(p1 >= a[i][0] && p2 >= a[i][1] && dp[i - 1][p1 - a[i][0]] == 1) {
                    for(int j = 0; j < b[i][0].size(); j++) {
                        ans.push_back(b[i][0][j]);
                    }
                    p1 -= a[i][0]; p2 -= a[i][1];
                }
                else if(p1 >= a[i][1] && p2 >= a[i][0] && dp[i - 1][p1 - a[i][1]] == 1) {
                    for(int j = 0; j < b[i][1].size(); j++) {
                        ans.push_back(b[i][1][j]);
                    }
                    p1 -= a[i][1]; p2 -= a[i][0];
                }
            }

            sort(ans.begin(), ans.end());
            for(int i = 0 ; i < ans.size(); i++)
                printf("%d\n", ans[i]);
            puts("end");
        }
    }

    return 0;
}

G - Supermarket

 POJ - 1456

A supermarket has a set Prod of products on sale. It earns a profit px for each product x∈Prod sold by a deadline dx that is measured as an integral number of time units starting from the moment the sale begins. Each product takes precisely one unit of time for being sold. A selling schedule is an ordered subset of products Sell ≤ Prod such that the selling of each product x∈Sell, according to the ordering of Sell, completes before the deadline dx or just when dx expires. The profit of the selling schedule is Profit(Sell)=Σ x∈Sellpx. An optimal selling schedule is a schedule with a maximum profit. 
For example, consider the products Prod={a,b,c,d} with (pa,da)=(50,2), (pb,db)=(10,1), (pc,dc)=(20,2), and (pd,dd)=(30,1). The possible selling schedules are listed in table 1. For instance, the schedule Sell={d,a} shows that the selling of product d starts at time 0 and ends at time 1, while the selling of product a starts at time 1 and ends at time 2. Each of these products is sold by its deadline. Sell is the optimal schedule and its profit is 80. 


Write a program that reads sets of products from an input text file and computes the profit of an optimal selling schedule for each set of products. 

Input

A set of products starts with an integer 0 <= n <= 10000, which is the number of products in the set, and continues with n pairs pi di of integers, 1 <= pi <= 10000 and 1 <= di <= 10000, that designate the profit and the selling deadline of the i-th product. White spaces can occur freely in input. Input data terminate with an end of file and are guaranteed correct.

Output

For each set of products, the program prints on the standard output the profit of an optimal selling schedule for the set. Each result is printed from the beginning of a separate line.

Sample Input

4  50 2  10 1   20 2   30 1

7  20 1   2 1   10 3  100 2   8 2
   5 20  50 10

Sample Output

80
185

Hint

The sample input contains two product sets. The first set encodes the products from table 1. The second set is for 7 products. The profit of an optimal schedule for these products is 185.

    本来一看题目这不是模拟贪心吗,Wa了之后想到如果时间t的商品有很多,那么时间t的时候可能是卖前面的、时间为t的以及卖比t大的,没法写。然后看题解是维护了一个答案优先队列,把商品根据时间排序,然后优先队列的体积代表了卖这些商品的时间,如果当前商品时间下限比优先队列体积大就进队列否则和队列的头结点比较价值,比队列头的价值大就替换。

    然后是并查集的解法。根据价值从大到小排序,对每个商品如果它之前的时间还有未被占用的,占用它并把该点往前连接。

//#include <cstdio>
//#include <cstring>
//#include <utility>
//#include <iostream>
//#include <map>
//#include <queue>
//#include <algorithm>
//#include <cmath>
//#include <string>
//#include <vector>
//using namespace std;
//typedef pair<double, double> P;
//typedef long long ll;
//#define N 10010
//#define M 2000100
//const int INF = 0x3f3f3f3f;
//const double eps = 1e-5;
//const double PI = acos(-1);
//#define fi first
//#define se second
//#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
//
//struct node {
//  int d, p;
//  bool operator < (const node & t) const {
//      return d < t.d;
//  }
//}pd[N];
//priority_queue<int, vector<int>, greater<int> > que;
//int n, ans;
//
//int main()
//{
//    #ifndef ONLINE_JUDGE
//    freopen("data.txt", "r", stdin);
//    #endif
//
//    while(~scanf("%d", &n)) {
//        while(!que.empty()) que.pop();
//        ans = 0;
//        rep(i, 1, n) {
//            scanf("%d%d", &pd[i].p, &pd[i].d);
//        }
//        sort(pd + 1, pd + 1 + n);
//        rep(i, 1, n) {
//            if(pd[i].d > que.size()) {
//                que.push(pd[i].p);
//                ans += pd[i].p;
//            }
//            else if(pd[i].p > que.top()){
//                ans += pd[i].p - que.top();
//                que.pop();
//                que.push(pd[i].p);
//            }
//        }
//        printf("%d\n", ans);
//    }
//
//    return 0;
//}
//

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 10010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct node {
  int d, p;
  bool operator < (const node & t) const {
      return p > t.p;
  }
}pd[N];
int F[N];
void init(){
    memset(F, -1, sizeof F);
}
int find(int x)
{
    if(-1 == F[x]) return x;
    return F[x] = find(F[x]);
}
int n, ans;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d", &n)) {
        ans = 0;
        rep(i, 1, n) {
            scanf("%d%d", &pd[i].p, &pd[i].d);
        }
        sort(pd + 1, pd + 1 + n);
        init();
        rep(i, 1, n) {
            int t = find(pd[i].d);
            if(t > 0) {
                ans += pd[i].p;
                F[t] = t - 1;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}

H - Parity game

 POJ - 1733

Now and then you play the following game with your friend. Your friend writes down a sequence consisting of zeroes and ones. You choose a continuous subsequence (for example the subsequence from the third to the fifth digit inclusively) and ask him, whether this subsequence contains even or odd number of ones. Your friend answers your question and you can ask him about another subsequence and so on. Your task is to guess the entire sequence of numbers. 

You suspect some of your friend's answers may not be correct and you want to convict him of falsehood. Thus you have decided to write a program to help you in this matter. The program will receive a series of your questions together with the answers you have received from your friend. The aim of this program is to find the first answer which is provably wrong, i.e. that there exists a sequence satisfying answers to all the previous questions, but no such sequence satisfies this answer.

Input

The first line of input contains one number, which is the length of the sequence of zeroes and ones. This length is less or equal to 1000000000. In the second line, there is one positive integer which is the number of questions asked and answers to them. The number of questions and answers is less or equal to 5000. The remaining lines specify questions and answers. Each line contains one question and the answer to this question: two integers (the position of the first and last digit in the chosen subsequence) and one word which is either `even' or `odd' (the answer, i.e. the parity of the number of ones in the chosen subsequence, where `even' means an even number of ones and `odd' means an odd number).

Output

There is only one line in output containing one integer X. Number X says that there exists a sequence of zeroes and ones satisfying first X parity conditions, but there exists none satisfying X+1 conditions. If there exists a sequence of zeroes and ones satisfying all the given conditions, then number X should be the number of all the questions asked.

Sample Input

10
5
1 2 even
3 4 odd
5 6 even
1 6 even
7 10 odd

Sample Output

3

又是区间那种题,但是这个区间的范围有点大,要离散化一下。只在线段树写过离散化。。。。。。Orz。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 5010
#define M 10100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int length, q, ans;
struct node {
  int u, v;
  bool flag;
}data[N];
char str[5];
int index[M], cnt;

int F[M];
bool R[N];
void init(int n) {
    rep(i, 0, cnt) F[i] = i, R[i] = 0;
}
int find(int x)
{
    if(x != F[x]) {
        int fa = F[x];
        F[x] = find(F[x]);
        R[x] = R[x] ^ R[fa];
    }
    return F[x];
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d", &length)) {
        scanf("%d", &q);
        cnt = 0;
        rep(i, 0, q - 1) {
            scanf("%d%d%s", &data[i].u, &data[i].v, str);
            data[i].flag = str[0] == 'o';
            data[i].u--;
            index[cnt++] = data[i].u;
            index[cnt++] = data[i].v;
        }

        sort(index, index + cnt);
        cnt = unique(index, index + cnt) - index;

        ans = 0;
        init(cnt);
        rep(i, 0, q - 1) {
            int u = lower_bound(index, index + cnt, data[i].u) - index;
            int v = lower_bound(index, index + cnt, data[i].v) - index;
            int ru = find(u), rv = find(v);

            if(ru == rv) {
                if(R[u] ^ R[v] != data[i].flag) break;
            }
            else {
                F[ru] = rv;
                R[ru] = R[u] ^ R[v] ^ data[i].flag;
            }
            ans++;
        }

        printf("%d\n", ans);
    }

    return 0;
}

I - Navigation Nightmare

 POJ - 1984

Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usually numbered/labeled 1..N. A series of M (1 <= M < 40,000) vertical and horizontal roads each of varying lengths (1 <= length <= 1000) connect the farms. A map of these farms might look something like the illustration below in which farms are labeled F1..F7 for clarity and lengths between connected farms are shown as (n):

	F1 --- (13) ---- F6 --- (9) ----- F3

            |                                 |

           (3)                                |

            |                                (7)

           F4 --- (20) -------- F2            |

            |                                 |

           (2)                               F5

            | 

           F7 


Being an ASCII diagram, it is not precisely to scale, of course.

Each farm can connect directly to at most four other farms via roads that lead exactly north, south, east, and/or west. Moreover, farms are only located at the endpoints of roads, and some farm can be found at every endpoint of every road. No two roads cross, and precisely one path
(sequence of roads) links every pair of farms.

FJ lost his paper copy of the farm map and he wants to reconstruct it from backup information on his computer. This data contains lines like the following, one for every road:

There is a road of length 10 running north from Farm #23 to Farm #17
There is a road of length 7 running east from Farm #1 to Farm #17
...

As FJ is retrieving this data, he is occasionally interrupted by questions such as the following that he receives from his navigationally-challenged neighbor, farmer Bob:

What is the Manhattan distance between farms #1 and #23?

FJ answers Bob, when he can (sometimes he doesn't yet have enough data yet). In the example above, the answer would be 17, since Bob wants to know the "Manhattan" distance between the pair of farms.
The Manhattan distance between two points (x1,y1) and (x2,y2) is just |x1-x2| + |y1-y2| (which is the distance a taxicab in a large city must travel over city streets in a perfect grid to connect two x,y points).

When Bob asks about a particular pair of farms, FJ might not yet have enough information to deduce the distance between them; in this case, FJ apologizes profusely and replies with "-1".

Input

	* Line 1: Two space-separated integers: N and M



* Lines 2..M+1: Each line contains four space-separated entities, F1,

        F2, L, and D that describe a road. F1 and F2 are numbers of

        two farms connected by a road, L is its length, and D is a

        character that is either 'N', 'E', 'S', or 'W' giving the

        direction of the road from F1 to F2.



* Line M+2: A single integer, K (1 <= K <= 10,000), the number of FB's

        queries



* Lines M+3..M+K+2: Each line corresponds to a query from Farmer Bob

        and contains three space-separated integers: F1, F2, and I. F1

        and F2 are numbers of the two farms in the query and I is the

        index (1 <= I <= M) in the data after which Bob asks the

        query. Data index 1 is on line 2 of the input data, and so on.

Output

	* Lines 1..K: One integer per line, the response to each of Bob's

        queries.  Each line should contain either a distance

        measurement or -1, if it is impossible to determine the

        appropriate distance.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6 1
1 4 3
2 6 6

Sample Output

13
-1
10

Hint

At time 1, FJ knows the distance between 1 and 6 is 13.
At time 3, the distance between 1 and 4 is still unknown.
At the end, location 6 is 3 units west and 7 north of 2, so the distance is 10.

哇这题是我自己想出来的哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈或或或,向量的转移什么的都是自己推出来的开心。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 40010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, m, k;
struct Node {
  int u, v, w, flag;
}data[N];
struct Question {
  int u, v, id;
  bool operator <(const Question & t) const {
      return id < t.id;
  }
}query[N];
char str[3];

int F[N], col[N], row[N];
void init()
{
    memset(col, 0, sizeof col);
    memset(row, 0, sizeof row);
    rep(i, 0, N - 1) F[i] = i;
}
int find(int x)
{
    if(x != F[x]) {
        int fa = F[x];
        F[x] = find(F[x]);
        col[x] += col[fa];
        row[x] += row[fa];
    }
    return F[x];
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d%d", &n, &m)) {
        rep(i, 0, m - 1) {
            scanf("%d%d%d%s", &data[i].u, &data[i].v, &data[i].w, str);
            if(str[0] == 'E') data[i].flag = 0;
            else if(str[0] == 'W') data[i].flag = 0, data[i].w *= -1;
            else if(str[0] == 'S') data[i].flag = 1;
            else data[i].flag = 1, data[i].w *= -1;
        }
        scanf("%d", &k);
        rep(i, 0, k - 1) {
            scanf("%d%d%d", &query[i].u, &query[i].v, &query[i].id);
        }
//cout << m <<' ' <<k <<endl;
        int l = 0;
        init();
        rep(i, 0, m - 1) {
            int u = data[i].u, v = data[i].v;
            int ru = find(u), rv = find(v);
            F[ru] = rv;
            if(data[i].flag){
                col[ru] = data[i].w + col[v] - col[u];
                row[ru] = row[v] - row[u];
            }
            else {
                row[ru] = data[i].w + row[v] - row[u];
                col[ru] = col[v] - col[u];
            }

            while(query[l].id == i + 1) {
                int ru = find(query[l].u), rv = find(query[l].v);
                if(ru != rv) puts("-1");
                else {
                    printf("%d\n", abs(col[query[l].u] - col[query[l].v]) + abs(row[query[l].u] - row[query[l].v]));
                }
                l++;
            }
        }
    }

    return 0;
}

J - A Bug's Life

 POJ - 2492

Background 
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs. 
Problem 
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.

Input

The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.

Output

The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.

Sample Input

2
3 3
1 2
2 3
1 3
4 2
1 2
3 4

Sample Output

Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!

Hint

Huge input,scanf is recommended.

分类问题,和食物链一样有偏移量法和开两个并查集的方法。集合方法直接做出来了,偏移量法有点懵逼。知道了异或和加和摸mod2的等价。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 2010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int t, n, m, a, b;
bool flag;

int F[N], R[N];
///When F[i] == i, R[i] == 0.
void init()
{
    memset(R, 0, sizeof R);
    rep(i, 0, N - 1) F[i] = i;
}
int find(int x)
{
    if(x != F[x]) {
        int fa = F[x];
        F[x] = find(F[x]);
        R[x] = R[fa]^R[x];
        ///if R[fa] was changed, R[x] should be changed, too.
    }
    return F[x];
}
bool unite(int x, int y)
{
    int rx = find(x), ry = find(y);
    if(rx == ry) {
        if(R[x] == R[y]) return false;
        else return true;
    }
    F[rx] = ry;
    R[rx] = R[y]^R[x]^1;
//    if R[x]==R[y], the sex between rx and ry should be diffrent because x and y are different.
//    if R[x]!=R[y], the sex between rx and ry should be the same.
    return true;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    scanf("%d", &t);
    rep(Case, 1, t) {
        scanf("%d%d", &n, &m);
        init();
        flag = false;
        rep(i, 1, m) {
            scanf("%d%d", &a, &b);
            if(flag) continue;
            if(!unite(a, b)) flag = true;
        }
        printf("Scenario #%d:\n", Case);
        if(flag) puts("Suspicious bugs found!");
        else puts("No suspicious bugs found!");
        printf("\n");
    }

    return 0;
}

//#include <cstdio>
//#include <cstring>
//#include <utility>
//#include <iostream>
//#include <map>
//#include <queue>
//#include <algorithm>
//#include <cmath>
//#include <string>
//#include <vector>
//using namespace std;
//typedef pair<int, int> P;
//typedef long long ll;
//#define N 4010
//#define M 2000100
//const int INF = 0x3f3f3f3f;
//const double eps = 1e-5;
//const double PI = acos(-1);
//#define fi first
//#define se second
//#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
//
//int t, n, m, a, b;
//bool flag;
//
//int F[N];
//void init(){
//    rep(i, 0, N - 1) F[i] = i;
//}
//int find(int x)
//{
//    if(x == F[x]) return x;
//    return F[x] = find(F[x]);
//}
//void unite(int x, int y)
//{
//    x = find(x); y = find(y);
//    if(x == y) return;
//    F[x] = y;
//}
//bool same(int x, int y){
//    return find(x) == find(y);
//}
//
//int main()
//{
//    #ifndef ONLINE_JUDGE
//    freopen("data.txt", "r", stdin);
//    #endif
//
//    scanf("%d", &t);
//    rep(Case, 1, t) {
//        scanf("%d%d", &n, &m);
//        init();
//        flag = false;
//        rep(i, 1, m) {
//            scanf("%d%d", &a, &b);
//            if(flag) continue;
//            if(same(a, b)) flag = true;
//            else {
//                unite(a, b + n);
//                unite(b, a + n);
//            }
//        }
//        printf("Scenario #%d:\n", Case);
//        if(flag) puts("Suspicious bugs found!");
//        else puts("No suspicious bugs found!");
//        printf("\n");
//    }
//
//    return 0;
//}

K - Rochambeau

 POJ - 2912

N children are playing Rochambeau (scissors-rock-cloth) game with you. One of them is the judge. The rest children are divided into three groups (it is possible that some group is empty). You don’t know who is the judge, or how the children are grouped. Then the children start playing Rochambeau game for M rounds. Each round two children are arbitrarily selected to play Rochambeau for one once, and you will be told the outcome while not knowing which gesture the children presented. It is known that the children in the same group would present the same gesture (hence, two children in the same group always get draw when playing) and different groups for different gestures. The judge would present gesture randomly each time, hence no one knows what gesture the judge would present. Can you guess who is the judge after after the game ends? If you can, after how many rounds can you find out the judge at the earliest?

Input

Input contains multiple test cases. Each test case starts with two integers N and M(1 ≤ N ≤ 500, 0 ≤ M ≤ 2,000) in one line, which are the number of children and the number of rounds. Following are M lines, each line contains two integers in [0, N) separated by one symbol. The two integers are the IDs of the two children selected to play Rochambeau for this round. The symbol may be “=”, “>” or “<”, referring to a draw, that first child wins and that second child wins respectively.

Output

There is only one line for each test case. If the judge can be found, print the ID of the judge, and the least number of rounds after which the judge can be uniquely determined. If the judge can not be found, or the outcomes of the M rounds of game are inconsistent, print the corresponding message.

Sample Input

3 3
0<1
1<2
2<0
3 5
0<1
0>1
1<2
1>2
0<2
4 4
0<1
0>1
2<3
2>3
1 0

Sample Output

Can not determine
Player 1 can be determined to be the judge after 4 lines
Impossible
Player 0 can be determined to be the judge after 0 lines

还以为是什么骚操作乱七八糟的加标记什么的,这竟然是枚举,有点暴力啊,,,还是要看数据量。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<double, double> P;
typedef long long ll;
#define N 50010
#define M 2000100
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N], R[N];
void init(int n){
    rep(i, 0, n) F[i] = i, R[i] = 0;
}
int find(int x)
{
    if(F[x] != x) {
        int fa = F[x];
        F[x] = find(F[x]);
        R[x] = (R[x] + R[fa]) % 3;
    }
    return F[x];
}
bool unite(int x, int y, int d)
{//cout << x <<' '<<y<<' ' <<d <<endl;
    int rx = find(x), ry = find(y);
    //cout << x <<' ' <<rx<<' ' <<y <<' ' <<ry<<' ' <<R[x]<<' ' <<R[y]<<endl;
    if(rx == ry) {
        return d == ((3 + R[x] - R[y]) % 3);
    }

    F[rx] = ry;
    R[rx] = (R[y] - R[x] + d + 3) % 3;
    return true;
}

int n, m, ans, cnt, line;
struct Node {
  int u, v, r;
}data[N];
char ch;

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(~scanf("%d%d", &n, &m)) {
        rep(i, 1, m) {
            cin >> data[i].u >> ch >> data[i].v;
            //cout << data[i].u <<' ' <<ch<<' ' <<data[i].v<<endl;
            if(ch == '<') data[i].r = 2;
            else if(ch == '=') data[i].r = 0;
            else if(ch == '>') data[i].r = 1;
        }

        ans = 0;
        cnt = 0;
        line = 0;
        rep(i, 0, n - 1) {
            init(n);
            bool flag = false;
            int tmp;
            rep(j, 1, m) {
                if(data[j].u == i || data[j].v == i) continue;
                int u = data[j].u, v = data[j].v, d = data[j].r;
                if(!unite(u, v, d)) {
                    flag = true;
                    tmp = j;
                    break;
                }
            }
            if(!flag) {
                cnt++; ans = i;
            }
            else line = max(line, tmp);
        }
        if(cnt == 0) puts("Impossible");
        else if(cnt >= 2) puts("Can not determine");
        else printf("Player %d can be determined to be the judge after %d lines\n", ans, line);
    }

    return 0;
}

L - Connections in Galaxy War

 ZOJ - 3261

In order to strengthen the defense ability, many stars in galaxy allied together and built many bidirectional tunnels to exchange messages. However, when the Galaxy War began, some tunnels were destroyed by the monsters from another dimension. Then many problems were raised when some of the stars wanted to seek help from the others.

In the galaxy, the stars are numbered from 0 to N-1 and their power was marked by a non-negative integer pi. When the star A wanted to seek help, it would send the message to the star with the largest power which was connected with star A directly or indirectly. In addition, this star should be more powerful than the star A. If there were more than one star which had the same largest power, then the one with the smallest serial number was chosen. And therefore, sometimes star A couldn't find such star for help.

Given the information of the war and the queries about some particular stars, for each query, please find out whether this star could seek another star for help and which star should be chosen.

Input

There are no more than 20 cases. Process to the end of file.

For each cases, the first line contains an integer N (1 <= N <= 10000), which is the number of stars. The second line contains N integers p0p1, ... , pn-1 (0 <= pi <= 1000000000), representing the power of the i-th star. Then the third line is a single integer M (0 <= M <= 20000), that is the number of tunnels built before the war. Then M lines follows. Each line has two integers ab (0 <= ab <= N - 1, a != b), which means star a and star b has a connection tunnel. It's guaranteed that each connection will only be described once.

In the (M + 2)-th line is an integer Q (0 <= Q <= 50000) which is the number of the information and queries. In the following Q lines, each line will be written in one of next two formats.

"destroy a b" - the connection between star a and star b was destroyed by the monsters. It's guaranteed that the connection between star a and star b was available before the monsters' attack.

"query a" - star a wanted to know which star it should turn to for help

There is a blank line between consecutive cases.

Output

For each query in the input, if there is no star that star a can turn to for help, then output "-1"; otherwise, output the serial number of the chosen star.

Print a blank line between consecutive cases.

Sample Input

2
10 20
1
0 1
5
query 0
query 1
destroy 0 1
query 0
query 1

Sample Output

1
-1
-1
-1

这个破坏边真是没法下手,题解竟然是逆向思维,这是道思维题Orz。先把最终要被破坏的边去掉不加进并查集,然后逆向操作遇到被毁坏的边就加进并查集。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10010
#define M 20010
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, p[N], m, nq;
P t[M];
struct Query {
  bool flag;
  int a, b;
}q[50010];
int ans[50010], l;
char str[10];
map<P, bool> mp;

int F[N];
void init(int n){
    rep(i, 0, n) F[i] = i;
}
int find(int x)
{
    if(x == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    int rx = find(x), ry = find(y);
    if(rx == ry) return;

    if(p[rx] < p[ry]) F[rx] = ry;
    else if(p[rx] > p[ry]) F[ry] = rx;
    else if(rx < ry) F[ry] = rx;
    else F[rx] = ry;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    bool flag = false;
    while(~scanf("%d", &n)) {
        if(flag) putchar('\n');
        flag = true;

        mp.clear();
        rep(i, 0, n - 1) scanf("%d", &p[i]);
        scanf("%d", &m);
        rep(i, 1, m) {
            scanf("%d%d", &t[i].fi, &t[i].se);
            if(t[i].fi > t[i].se) swap(t[i].fi, t[i].se);
        }
        scanf("%d", &nq);
        rep(i, 1, nq) {
            scanf("%s", str);
            if(str[0] == 'q') scanf("%d", &q[i].a), q[i].flag = false;
            else {
                scanf("%d%d", &q[i].a, &q[i].b);
                if(q[i].a > q[i].b) swap(q[i].a, q[i].b);
                mp[P(q[i].a, q[i].b)] = q[i].flag = true;
            }
        }

        init(n);
        rep(i, 1, m) {
            if(!mp[t[i]]) {
                unite(t[i].fi, t[i].se);
            }
        }

        l = 0;
        for(int i = nq; i >= 1; i--) {
            if(q[i].flag) unite(q[i].a, q[i].b);
            else {
                int ra = find(q[i].a);
                if(p[ra] > p[q[i].a]) ans[l++] = ra;
                //if(ra == q[i].a || p[ra] == p[q[i].a]) ans[l++] = -1;
                else ans[l++] = -1;
            }
        }

        for(int i = l - 1; i >= 0; i--)
            printf("%d\n", ans[i]);
    }

    return 0;
}

M - 小希的迷宫

 HDU - 1272

上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。 
 

Input

输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。 
整个文件以两个-1结尾。 

Output

对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"Yes",否则输出"No"。 

Sample Input

6 8  5 3  5 2  6 4
5 6  0 0

8 1  7 3  6 2  8 9  7 5
7 4  7 8  7 6  0 0

3 8  6 8  6 4
5 3  5 6  5 2  0 0

-1 -1

Sample Output

Yes
Yes
No

突然来了简单题舒坦。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 100010
#define M 20010
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int F[N];
bool vis[N];
void init()
{
    memset(vis, false, sizeof vis);
    rep(i, 0, N - 1) F[i] = i;
}
int find(int x)
{
    if(x == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    int rx = find(x), ry = find(y);
    if(rx == ry) return;
    F[rx] = ry;
}
bool same(int x, int y) {
    return find(x) == find(y);
}

int a, b;
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    while(scanf("%d%d", &a, &b) && a != -1) {
        init();
        bool flag = true;
        while(a != 0) {
            if(same(a, b)) flag = false;
            else unite(a, b);
            vis[a] = true; vis[b] = true;
            scanf("%d%d", &a, &b);
        }
        int cnt = 0;
        rep(i, 1, N) {
            if(vis[i] && find(i) == i) cnt++;
        }
        if(cnt > 1) flag = false;
        printf(flag?"Yes\n":"No\n");
    }

    return 0;
}

N - Is It A Tree?

 POJ - 1308

A tree is a well-known data structure that is either empty (null, void, nothing) or is a set of one or more nodes connected by directed edges between nodes satisfying the following properties. 

There is exactly one node, called the root, to which no directed edges point. 
Every node except the root has exactly one edge pointing to it. 
There is a unique sequence of directed edges from the root to each node. 
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not. 


In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not.

Input

The input will consist of a sequence of descriptions (test cases) followed by a pair of negative integers. Each test case will consist of a sequence of edge descriptions followed by a pair of zeroes Each edge description will consist of a pair of integers; the first integer identifies the node from which the edge begins, and the second integer identifies the node to which the edge is directed. Node numbers will always be greater than zero.

Output

For each test case display the line "Case k is a tree." or the line "Case k is not a tree.", where k corresponds to the test case number (they are sequentially numbered starting with 1).

Sample Input

6 8  5 3  5 2  6 4
5 6  0 0

8 1  7 3  6 2  8 9  7 5
7 4  7 8  7 6  0 0

3 8  6 8  6 4
5 3  5 6  5 2  0 0
-1 -1

Sample Output

Case 1 is a tree.
Case 2 is a tree.
Case 3 is not a tree.

和上一题一样,改了个输出。有向图的环要用最短路算法判。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <queue>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10010
#define M 20010
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const double PI = acos(-1);
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, p[N], m, nq;
P t[M];
struct Query {
  bool flag;
  int a, b;
}q[50010];
int ans[50010], l;
char str[10];
map<P, bool> mp;

int F[N];
void init(int n){
    rep(i, 0, n) F[i] = i;
}
int find(int x)
{
    if(x == F[x]) return x;
    return F[x] = find(F[x]);
}
void unite(int x, int y)
{
    int rx = find(x), ry = find(y);
    if(rx == ry) return;

    if(p[rx] < p[ry]) F[rx] = ry;
    else if(p[rx] > p[ry]) F[ry] = rx;
    else if(rx < ry) F[ry] = rx;
    else F[rx] = ry;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif

    bool flag = false;
    while(~scanf("%d", &n)) {
        if(flag) putchar('\n');
        flag = true;

        mp.clear();
        rep(i, 0, n - 1) scanf("%d", &p[i]);
        scanf("%d", &m);
        rep(i, 1, m) {
            scanf("%d%d", &t[i].fi, &t[i].se);
            if(t[i].fi > t[i].se) swap(t[i].fi, t[i].se);
        }
        scanf("%d", &nq);
        rep(i, 1, nq) {
            scanf("%s", str);
            if(str[0] == 'q') scanf("%d", &q[i].a), q[i].flag = false;
            else {
                scanf("%d%d", &q[i].a, &q[i].b);
                if(q[i].a > q[i].b) swap(q[i].a, q[i].b);
                mp[P(q[i].a, q[i].b)] = q[i].flag = true;
            }
        }

        init(n);
        rep(i, 1, m) {
            if(!mp[t[i]]) {
                unite(t[i].fi, t[i].se);
            }
        }

        l = 0;
        for(int i = nq; i >= 1; i--) {
            if(q[i].flag) unite(q[i].a, q[i].b);
            else {
                int ra = find(q[i].a);
                if(p[ra] > p[q[i].a]) ans[l++] = ra;
                //if(ra == q[i].a || p[ra] == p[q[i].a]) ans[l++] = -1;
                else ans[l++] = -1;
            }
        }

        for(int i = l - 1; i >= 0; i--)
            printf("%d\n", ans[i]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40379678/article/details/81630336
今日推荐