Educational Codeforces Round 10 E - Pursuit For Artifacts (强联通缩点 + 回溯)

题目链接:http://codeforces.com/contest/652/problem/E

给你n个点m个边,x和y双向连接,要是z是1表示这条边上有宝藏,0则没有,最后给你起点和终点,问你要是到从起点到终点要是中间遇到宝藏就输出YES,否则就输出NO。

每条边只能经过一次,而且这个图保证连通的。

我用tarjan强连通缩点,把这个图变成一棵树,要是起点终点在一个连通分量里且分量里的边有宝藏,那么就输出YES。否则,就找起点到终点直接的路有没有宝藏,因为缩点之后是一棵树,所以起点和终点只有一条路。那我从起点dfs一遍,par[i]记录的是i前驱节点。那我之后就从终点反向遍历这条路,要是路上有宝藏,就输出YES。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <set>
  6 using namespace std;
  7 const int MAXN = 3e5 + 10;
  8 typedef pair <int , int> P;
  9 struct data {
 10     int next , to , art;
 11 }edge[MAXN * 2];
 12 int head[MAXN] , low[MAXN] , dfn[MAXN] , st[MAXN] , block[MAXN] , p[MAXN];
 13 int top , ord , sccnum , end_point , cont;
 14 bool instack[MAXN] , vis[MAXN] , ok , res;
 15 vector <P> G[MAXN];
 16
 17 void init() {
 18     memset(head , -1 , sizeof(head));
 19 }
 20
 21 inline void add(int u , int v , int art) {
 22     edge[cont].next = head[u];
 23     edge[cont].to = v;
 24     edge[cont].art = art;
 25     head[u] = cont++;
 26 }
 27
 28 void tarjan(int u , int par) {
 29     low[u] = dfn[u] = ++ord;
 30     st[++top] = u;
 31     instack[u] = true;
 32     for(int i = head[u] ; ~i ; i = edge[i].next) {
 33         int v = edge[i].to;
 34         if(v == par)
 35             continue;
 36         if(!dfn[v]) {
 37             tarjan(v , u);
 38             low[u] = min(low[v] , low[u]);
 39         }
 40         else if(instack[v]) {
 41             low[u] = min(low[u] , dfn[v]);
 42         }
 43     }
 44     if(dfn[u] == low[u]) {
 45         sccnum++;
 46         int v;
 47         do {
 48             v = st[top--];
 49             instack[v] = false;
 50             block[v] = sccnum;
 51         }while(u != v);
 52     }
 53 }
 54
 55 void dfs(int u , int par) {
 56     p[u] = par;
 57     for(int i = 0 ; i < G[u].size() ; i++) {
 58         int v = G[u][i].first;
 59         if(par == v)
 60             continue;
 61         if(G[u][i].second)
 62             vis[v] = true;
 63         dfs(v , u);
 64     }
 65 }
 66
 67 int main()
 68 {
 69     int n , m , u , v , art , s , e , heheda = 1;
 70     scanf("%d %d" , &n , &m);
 71     init();
 72     for(int i = 0 ; i < m ; i++) {
 73         scanf("%d %d %d" , &u , &v , &art);
 74         add(u , v , art);
 75         add(v , u , art);
 76         if(art == 1)
 77             heheda = 0;
 78     }
 79     scanf("%d %d" , &s , &e);
 80     if(heheda) {
 81         printf("NO\n");
 82         return 0;
 83     }
 84     tarjan(1 , -1);
 85     end_point = block[e];
 86     for(int u = 1 ; u <= n ; u++) {
 87         for(int i = head[u] ; ~i ; i = edge[i].next) {
 88             int v = edge[i].to;
 89             if(block[u] != block[v]) {
 90                 G[block[u]].push_back(P(block[v] , edge[i].art));
 91             }
 92             else {
 93                 if(!vis[block[u]])
 94                     vis[block[u]] = (bool)(edge[i].art);
 95             }
 96         }
 97     }
 98     if(block[s] == end_point && vis[block[s]]) {
 99         printf("YES\n");
100         return 0;
101     }
102     if(vis[block[s]])
103         res = true;
104     dfs(block[s] , -1);
105     for(int i = end_point ; ~i ; i = p[i]) {
106         if(vis[i])
107             res = true;
108     }
109     if(res)
110         printf("YES\n");
111     else
112         printf("NO\n");
113 }
时间: 2024-12-28 05:56:48

Educational Codeforces Round 10 E - Pursuit For Artifacts (强联通缩点 + 回溯)的相关文章

Educational Codeforces Round 10 D. Nested Segments (树状数组)

题目链接:http://codeforces.com/problemset/problem/652/D 给你n个不同的区间,L或者R不会出现相同的数字,问你每一个区间包含多少个区间. 我是先把每个区间看作整体,按照R从小到大排序.然后从最小的R开始枚举每个区间,要是枚举到这个区间L的时候,计算之前枚举的区间有多少个Li在L之后,那么这些Li大于L的区间的数量就是答案.那我每次枚举的时候用树状数组add(L , 1) 说明在L这个位置上出现了区间,之后枚举的时候计算L之前的和,然后i - 1 -

CF Educational Codeforces Round 10 D. Nested Segments 离散化+树状数组

题目链接:http://codeforces.com/problemset/problem/652/D 大意:给若干个线段,保证线段端点不重合,问每个线段内部包含了多少个线段. 方法是对所有线段的端点值离散化,按照左端点从大到小排序,顺着这个顺序处理所有线段,那么满足在它内部的线段一定是之前已经扫到过的.用树状数组判断有多少是在右端点范围内. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

Educational Codeforces Round 10 A B题、

A. Gabriel and Caterpillar 题意: 就是说  一个小孩子去观察毛毛虫从 h1的地方爬到h2的地方.毛毛虫从10点爬到22点.每小时爬的距离是a, 晚上22点到第二天早上10点 毛毛虫休息 每小时下落b距离.但是最初状态是那个小孩子从14点开始观察毛毛虫的, 必须过了24点才算一天 思路:模拟.但细节地方要注意 hint:但你要知道什么情况下永远也爬不上去,就是说每小时下落比每小时上升的距离大呢,但这还有个细节, 就是即使b>a 但毛毛虫是先可以爬10个小时,如果在这10

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 26 D. Round Subset(dp)

题目链接:Educational Codeforces Round 26 D. Round Subset 题意: 给你n个数,让你选其中的k个数,使得这k个数的乘积的末尾的0的个数最大. 题解: 显然,末尾乘积0的个数和因子2和因子5的个数有关. 然后考虑dp[i][j]表示选i个数,当前因子5的个数为j时,能得到因子2最多的为多少. 那么对于每个数,记录一下因子2和5的个数,做一些01背包就行了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) me

CodeForces 837F - Prefix Sums | Educational Codeforces Round 26

按tutorial打的我血崩,死活挂第四组- - 思路来自FXXL /* CodeForces 837F - Prefix Sums [ 二分,组合数 ] | Educational Codeforces Round 26 题意: 设定数组 y = f(x) 使得 y[i] = sum(x[j]) (0 <= j < i) 求初始数组 A0 经过多少次 f(x) 后 会有一个元素 大于 k 分析: 考虑 A0 = {1, 0, 0, 0} A1 = {1, 1, 1, 1} -> {C(

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Educational Codeforces Round 23 D. Imbalanced Array(单调栈)

题目链接:Educational Codeforces Round 23 D. Imbalanced Array 题意: 给你n个数,定义一个区间的不平衡因子为该区间最大值-最小值. 然后问你这n个数所有的区间的不平衡因子和 题解: 对每一个数算贡献,a[i]的贡献为 当a[i]为最大值时的 a[i]*(i-l+1)*(r-i+1) - 当a[i]为最小值时的a[i]*(i-l+1)*(r-i+1). 计算a[i]的l和r时,用单调栈维护.具体看代码,模拟一下就知道了. 然后把所有的贡献加起来.

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu