2018-5-30 總結

2018-5-21 ~ 2018-5-30集訓感想

 

首先 感謝 xiaoyao24256大佬 給個人blog(雖然只用一天QWQ)ios

 

這幾天來到了浙江集訓 爽爆(假的qwq)c++

儘管這幾天學到了好多知識 但我仍是個蒟蒻555算法

 

從5.29的ACM賽先說吧數組

比賽名稱叫ACM歡樂賽,作題不歡樂,可是吃KFC吃的很歡樂嘿嘿嘿優化

 

一開始的時候 咱們小組比其餘小組早A了前2道題(雖然不是最先)ui

而後而後而後我就很開心spa

 

因而咱們就卡在了第三題……code

咱們組一個大佬想出來了一個gcd的算法(我不會告訴你他就是給我號的人)blog

結果不知道什麼玄學緣由 咱們組否定了這個算法 去剛第四題排序

爲何要否定呢?我也不知道啊……鬼知道那就是正解qwq

附上核心代碼

 1 read(p) , read(q) , read(b);
 2         
 3 register ll Gcd = gcd(p,q);
 4 q /= Gcd;
 5 Gcd = b;
 6         
 7 for(; q!=-1; ) {
 8     Gcd = gcd(q,Gcd);
 9     q /= Gcd;
10     if(Gcd == 1)    break;
11 }
12         
13 if(q == 1)    puts("Finite");
14 else    puts("Infinite");

 

 

第四題……不想說什麼了

我推了快1個小時的數學解

而後推出來了一個玄學的東西:

if len%4 == 1 輸出頭尾各一個數

if len%4 == 2 輸出頭尾各2個數

if len%4 == 3 輸出第一個數、第三個數、倒1、倒三這些數

if len%4 == 0 輸出全部數

正當我推得很是開心的時候 驗證了下len=12的狀況

而後就發現這個作法是錯誤的

因而 MMP ……

比賽結束以後我才發現這道是一道很是!水的!區間DP

哇哇哇氣死了

依然附上代碼

1 for(register int i=n-1; i>=1; i--) {
2     for(register int j=i+1; j<=n; j++) {
3         f[i][j] = f[i][j-1] ^ f[i+1][j];
4         g[i][j] = maxest(f[i][j],g[i][j-1],g[i+1][j]);
5     }
6 }

 

 

咱們最後選擇直接去看第7題(垃圾AtCoder)

想出了兩個相似正解的方法

嗯其實不是正解 最後測了WA的不要不要的

逃)

嗯那兩個算法就是打表和隨機數

事實證實打表能過更多的點

誒呀打表是我想出來的~

我以爲我能夠把表交上來

嗯算了太大了不交了qwq

我不會告訴你我其實在湊字數

 

好了好了咱們來說一下正事吧

 

線段樹

對這就是一個很神奇的東西

咱們先來引入一個題目:戳我

假如說這道題目沒有修改這這個操做,咱們用前綴和維護一下就好了

加了修改以後,咱們能想到的最樸素的作法是什麼呢?
固然就是枚舉 L - R 之間每一個數而後加上x

求和也是一項一項加起來,這樣複雜的是O(N^2)的

一看數據,喊出GG~

那咱們有沒有什麼奇技淫巧下降複雜度呢?

線段樹就是爲了這個而生的。

就讓我來簡介一下線段樹吧:

線段樹是一個二叉樹,每一個子節點裏存放一段區間的左右邊界還有子節點的信息,能夠是一段區間的和、最大值、最小值等等等等

爲了更好的理解線段樹,我厚顏無恥的拿了網上某個大佬的圖來解釋

算了中間一堆能夠介紹的如今也寫不了了,就不介紹了,有沒感受本身期待了半天卻……嗯哼~

我直接貼代碼了欸嘿

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstdio>
 4 
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 const int Maxn = 400010;
 9 int n , m;
10 int a[Maxn];
11 struct SegmentTree {
12     ll sum;    /* 1的總數 */
13     ll tag;    /* 標記 */
14     int leftbound;
15     int rightbound;
16 } Tree[Maxn];
17 
18 inline void Build(int root, int left , int right) {
19     
20     Tree[root].leftbound = left;
21     Tree[root].rightbound = right;
22     if(left == right)    Tree[root].sum = a[left];
23     else {
24         register int Mid = ( left + right ) / 2;
25         Build(root*2,left,Mid);
26         Build(root*2+1,Mid+1,right);
27         Tree[root].sum = Tree[root*2].sum + Tree[root*2+1].sum;
28     }
29     
30 }
31 
32 inline void Downtag(int root) {
33     
34     if(Tree[root].tag) {
35         Tree[root*2].tag += Tree[root].tag;
36         Tree[root*2+1].tag += Tree[root].tag;
37         Tree[root*2].sum += ( Tree[root*2].rightbound - Tree[root*2].leftbound + 1 ) * Tree[root].tag;
38         Tree[root*2+1].sum += ( Tree[root*2+1].rightbound - Tree[root*2+1].leftbound + 1 ) * Tree[root].tag;
39         Tree[root].tag = 0;
40     }
41     
42 }
43 
44 inline void Modify(int root , int left , int right , int delta) {
45     
46     if(Tree[root].leftbound >= left && Tree[root].rightbound <= right) {
47         Tree[root].tag += delta;
48         Tree[root].sum += ( Tree[root].rightbound - Tree[root].leftbound + 1 ) * delta;
49     } else {
50         Downtag(root);
51         register int Mid = ( Tree[root].leftbound + Tree[root].rightbound ) / 2;
52         if(left <= Mid)    Modify(root*2,left,right,delta);
53         if(right > Mid)    Modify(root*2+1,left,right,delta);
54         Tree[root].sum = Tree[root*2].sum + Tree[root*2+1].sum;
55     }
56     
57 }
58 
59 inline ll Query(int root , int left , int right) {
60     
61     if(Tree[root].leftbound >= left && Tree[root].rightbound <= right) {
62         return Tree[root].sum;
63     } else {
64         Downtag(root);
65         register ll ans = 0;
66         register int Mid = ( Tree[root].leftbound + Tree[root].rightbound ) / 2;
67         if(left <= Mid)    ans += Query(root*2,left,right);
68         if(right > Mid)    ans += Query(root*2+1,left,right);
69         return ans;
70     }
71     
72 }
73 
74 int main() {
75     
76     scanf("%d%d",&n,&m);
77     
78     for(register int i=1; i<=n; i++)
79         scanf("%d",&a[i]);
80     
81     Build(1,1,n);
82     
83     for(register int i=1,x,y,z,k; i<=m; i++) {
84         scanf("%d%d%d",&z,&x,&y);
85         if(z == 1) {
86             scanf("%d",&k);
87             Modify(1,x,y,k);
88         } else    printf("%lld\n",Query(1,x,y));
89     }
90     
91     return 0;
92     
93 }

額開頭那個氧氣優化別在乎哈~

樹狀數組

這個東西嘛

跟線段樹很像的

就是用一個lowbit瞎**搞

而後利用logn的時間求出來

這裏放一個題目:戳我

代碼以下qwq

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std ;
 4 
 5 const int MAXN = 500010;
 6 int n,m;
 7 int a[MAXN];
 8 int c[MAXN];
 9 
10 inline void read(int &x) {
11     int num = 0 , negative = 0;
12     char ch = getchar();
13     
14     while((ch < '0' || ch > '9') && ch != '-')
15         ch = getchar();
16     
17     if(ch == '-')    negative = 1;
18     else    num = ch - '0';
19     
20     ch = getchar();
21     
22     while(ch >= '0' && ch <= '9') {
23         num = num * 10 + ch - '0';
24         ch = getchar();
25     }
26     
27     x = num;
28     if(negative)
29         x = -x;
30 }
31 
32 inline int lowbit(int x) {
33     return x & (-x);
34 }
35 
36 inline int sum(int x) {
37     int ans = 0;
38     for(int i=x; i>0; i-=lowbit(i))
39         ans += c[i];
40     return ans;
41 }
42 
43 inline void add(int x , int y) {
44     for(int i=x; i<=n; i+=lowbit(i))
45         c[i] += y;
46 }
47 
48 int main() {
49     
50     read(n) , read(m);
51     for(int i=1; i<=n; i++) {
52         read(a[i]);
53         add(i,a[i]);
54     }
55     
56     for(int i=1,z,x,y; i<=m; i++) {
57         read(z) , read(x) , read(y);
58         if(z == 1)    add(x,y);
59         if(z == 2)    printf("%d\n",sum(y) - sum(x-1));
60     }
61     
62     return 0;
63     
64 }

講個笑話,樹狀數組的題都能用線段樹短

那爲何咱們還要樹狀數組呢?

固然是由於代碼短、更好寫了啦~

 

LCA 最近公共祖先問題

例題:戳我

 

LCA 是什麼意思呢 Largest China Apple?

哦哦哦哦哦不對固然不是這樣

求出最近公共祖先有什麼tarjan算法,還要什麼病茶几and check

本蒟蒻這裏就不介紹了,這裏介紹一個倍增的算法

倍增呢,是一個神奇的東西,就是把2^p化成2^(p-1) + 2^(p-1)

而後瞎**搞啦!

附上代碼

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cmath>
 5 
 6 using namespace std;
 7 
 8 const int Maxn = 500010;
 9 int n , m , s , tot , maxdep;
10 int last[Maxn];
11 int depth[Maxn];    /* depth[i] : i的深度 */
12 int f[Maxn][20];    /* f[i][k] : i的第2^k祖先 */
13 
14 struct Edge {
15     int to;
16     int next;
17 } e[Maxn*2];
18 
19 inline void add(int u , int v) {
20     tot ++;
21     e[tot].to = v;
22     e[tot].next = last[u];
23     last[u] = tot;
24 }
25 
26 inline void dfs(int x , int fa) {
27     
28     depth[x] = depth[fa] + 1;
29     maxdep = max(maxdep,depth[x]);
30     f[x][0] = fa;
31     
32     for(register int i=1; (1<<i)<=depth[x]; i++)
33         f[x][i] = f[f[x][i-1]][i-1];
34     /* x的第2^k祖先 = x的第2^(k-1)祖先的第2^(k-1)祖先 */
35     
36     for(register int i=last[x]; i; i=e[i].next) {
37         register int y = e[i].to;
38         if(y != fa)    dfs(y,x);    /* 遍歷兒子 */
39     }
40     
41 }
42 
43 inline int lca(int a , int b) {
44     
45     if(a == b)    return a;
46     if(depth[a] > depth[b])    swap(a,b);
47     
48     for(register int i=maxdep; i>=0; i--)
49         if(depth[a] <= depth[b] - (1<<i))
50             b = f[b][i];
51     /* 一個數必定會由2^k+2^m+2^p+...組成
52        a的深度和b的深度的差距也必定會由2^k+2^m+2^p+...組成
53        因此最終必定會到同一層 */
54     
55     if(a == b)    return a;
56     
57     for(register int i=maxdep; i>=0; i--) {
58         if(f[a][i] == f[b][i])    continue;    /* continue的做用是找a和b的最近祖先 */
59         else    a = f[a][i] , b = f[b][i];
60     }
61     
62     return f[a][0];
63     
64 }
65 
66 int main() {
67     
68     scanf("%d%d%d",&n,&m,&s);
69     for(register int i=1,x,y; i<n; i++) {
70         scanf("%d%d",&x,&y);
71         add(x,y);
72         add(y,x);
73     }
74     
75     dfs(s,0);
76     
77     maxdep = log2(maxdep);
78     for(register int u,v; m--; ) {
79         scanf("%d%d",&u,&v);
80         printf("%d\n",lca(u,v));
81     }
82     
83     return 0;
84     
85 }

 

這裏插一句,集訓的時候咱們去了上海交♂大和上海鈕釦大學啊呸

而後身份證丟了……爲何呢?無可奉告。

最後仍是感謝海亮的老師們,幫我各類聯繫找到了身份證

就不用用半條命換錢包了

 

數論~

數論固然不是一個算法啦

當時就是萬惡的數論害的我……哇嗚嗚嗚嗚不說了

這裏說個exgcd,擴展歐幾里得算法

證實能夠說是能用幾個詞來形容了

就是 naive 顯而易見 易證 輕鬆的獲得了啦

啊呸啊呸我都說了什麼

好了 我搞個板子下來 湊個字數啦~

 1 template < typename Typ >
 2 inline Typ exgcd(Typ a , Typ b , Typ &x , Typ &y) {
 3     
 4     if(!b) {
 5         x = (Typ)1;
 6         y = (Typ)0;
 7         return a;
 8     }
 9     
10     register Typ Gcd = exgcd(b,a%b,x,y);
11     
12     register Typ tmp = x;
13     x = y;
14     y = tmp - a / b * y;
15     
16     return Gcd;
17     
18 }

template那一行是什麼意思呢?

一站式知足:戳我

沒想到吧 ->此處省略邪笑

 

manacher和kmp算法

簡稱馬拉車和看*片 

馬拉車例題:戳我,看*片例題:戳我

你什麼都沒聽到qwq

這兩個算法是我見過的很玄學的算法

已經懶了,因此有代碼qwq

先是馬拉車

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstring> 
 4 #include <cstdio>
 5 
 6 const int Maxn = 11000010;
 7 char s[Maxn];
 8 int pal[2*Maxn];
 9 
10 inline void read() {
11     
12     register int len = -1;
13     register char ch = getchar();
14     
15     while(ch != EOF) {
16         s[++len] = ch;
17         ch = getchar();
18     }
19     
20 }
21 
22 int main() {
23     
24     read();
25     
26     register int len = strlen(s);
27     
28     register int l = -1 , r = -1 , ans = 0;
29     
30     for(register int z=0; z<2*len; z++) {
31         register int i = ( z + 1 ) >> 1;
32         register int j = z >> 1;
33         register int p = 0;
34         if(i < r)    p = std :: min(r-i,pal[2*(l+r)-z]);
35         while(j+p+1 < len && i-p-1 >= 0 && s[j+p+1] == s[i-p-1])    p ++;
36         if (j + p > r) {
37             r = j + p;
38             l = i - p;
39         }
40         pal[z] = p;
41         register int tmp = 2 * p + 1;
42         if( z & 1 )    tmp --;
43         ans = std :: max(ans,tmp);
44     }
45     
46     printf("%d\n",ans);
47     
48     return 0;
49     
50 }

而後看*片

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstdio>
 4 
 5 using namespace std;
 6 
 7 const int Maxn = 1000010;
 8 int len1 , len2;
 9 string x , y , a , b;
10 int next[Maxn];
11 
12 int main() {
13     
14     cin >> a >> b;
15     
16     len1 = a.size();
17     len2 = b.size();
18     
19     x.resize(len1);
20     y.resize(len2);
21     
22     for(register int i=1; i<=len1; i++)    x[i] = a[i-1];
23     for(register int i=1; i<=len2; i++)    y[i] = b[i-1];
24     
25     next[1] = 0;
26     
27     for(register int i=2,j=0; i<=len2; i++) {
28         while(j && y[i] != y[j+1])    j = next[j];
29         if(y[i] == y[j+1])    j ++;
30         next[i] = j;
31     }
32     
33     for(register int i=1,j=0; i<=len1; i++) {
34         while(j && x[i] != y[j+1])    j = next[j];
35         if(x[i] == y[j+1])    j ++;
36         if(j == len2) {
37             printf("%d\n",i-len2+1);
38             j = next[j];
39         }
40     }
41     
42     for(register int i=1; i<=len2; i++)
43         printf("%d ",next[i]);
44     putchar('\n');
45     
46     return 0;
47     
48 }

wow~我湊了好多字啦

啊呸啊呸沒什麼

 

下面講一個很是容易理解的字符串算法

猜猜看是什麼?

 

Trie樹

簡單介紹下,就是把字符串每一個字符弄成個子節點,而後暴力遍歷一遍就好了

模板題:戳我

沒想到吧!題目名稱這麼怪

我又要想個藉口貼模板啦!嗯就是這題比較簡單

因而上~模~板~

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 
 6 using namespace std;
 7 
 8 const int Maxn = 10010;
 9 const int Son = 30;
10 int n , m , num;
11 struct Trie {
12     bool flag;
13     bool first;
14     int son[Son];
15 } t[Maxn*50];
16 
17 inline void insert(string s) {
18     
19     register int u = 0;
20     register int len = s.size();
21     
22     for(register int i=0; i<len; i++) {
23         register int v = int ( s[i] - 'a' + 1 );
24         if(!t[u].son[v])    t[u].son[v] = ++ num;
25         u = t[u].son[v];
26     }
27     
28     t[u].flag = true;
29     
30 }
31 
32 inline int query(string s) {
33     
34     register int u = 0;
35     register int len = s.size();
36     register int state = 0;
37     
38     for(register int i=0; i<len; i++) {
39         register int v = int ( s[i] - 'a' + 1 );
40         if(!t[u].son[v])    return 1;
41         u = t[u].son[v];
42     }
43     
44     if(!t[u].flag)    return 1;
45     if(t[u].first)    return 2;
46     t[u].first = true;
47     return 0;
48     
49 }
50 
51 int main() {
52     
53     register string name;
54     
55     scanf("%d",&n);
56     for(register int i=1; i<=n; i++) {
57         cin >> name;
58         insert(name);
59     }
60     scanf("%d",&m);
61     for(; m--; ) {
62         cin >> name;
63         register int state = query(name);
64         if(!state)    puts("OK");
65         else if(state == 1)    puts("WRONG");
66         else    puts("REPEAT");
67     }
68     
69     return 0;
70     
71 }

 全新算法:AC自動機

這個算法很神奇,只要交上去就會自動A題,分分鐘成爲Rank1,媽媽不再用擔憂個人OI生活啦

等下。。。看錯算法了,那個算法是自動AC機QWQ

這個算法呢,就是要你熟練的掌握看*片算法和Trie樹

而後結合起來跑一遍就好了

有2道模板題:

簡單版:戳我  提升版:戳我

不用說的啦~先附上代碼~

簡單版:

 1 // luogu-judger-enable-o2
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <queue>
 5 
 6 using namespace std;
 7 
 8 const int Maxn = 1000010;
 9 const int Maxm = 30;
10 int n , cnt;
11 
12 struct Trie {
13     int fail;
14     int end;
15     int num[Maxm];
16 } t[Maxn];
17 
18 inline void Build(string s) {
19     
20     register int len = s.size();
21     register int now = 0;
22     
23     for(register int i=0; i<len; i++) {
24         register int to = s[i] - 'a' + 1;
25         if(!t[now].num[to])    t[now].num[to] = ++ cnt;
26         now = t[now].num[to];
27     }
28     
29     t[now].end ++;
30     
31 }
32 
33 inline void Getfail() {
34     
35     queue <int> Q;
36     
37     for(register int i=1; i<=26; i++) {
38         if(t[0].num[i]) {
39             t[t[0].num[i]].fail = 0;
40             Q.push(t[0].num[i]);
41         }
42     }
43     
44     while(!Q.empty()) {
45         register int now = Q.front();
46         Q.pop();
47         for(register int i=1; i<=26; i++) {
48             if(t[now].num[i]) {
49                 t[t[now].num[i]].fail = t[t[now].fail].num[i];
50                 Q.push(t[now].num[i]);
51             } else    t[now].num[i] = t[t[now].fail].num[i];
52         }
53     }
54     
55 }
56 
57 inline int Query(string s) {
58     
59     register int len = s.size();
60     register int now = 0 , ans = 0;
61     
62     for(register int i=0; i<len; i++) {
63         register int to = s[i] - 'a' + 1;
64         now = t[now].num[to];
65         for(register int j=now; j&&t[j].end; j=t[j].fail) {
66             ans += t[j].end;
67             t[j].end = 0;
68         }
69     }
70     
71     return ans;
72     
73 }
74 
75 int main() {
76     
77     register string s;
78     
79     scanf("%d",&n);
80     for(register int i=1; i<=n; i++) {
81         cin >> s;
82         Build(s);
83     }
84     
85     t[0].fail = 0;
86     
87     Getfail();
88     
89     cin >> s;
90     
91     cout << Query(s) << endl;
92     
93     return 0;
94     
95 }

吐槽一句luogu數據貌似有點水嗯哼

如今來提升版:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <queue>
  6 
  7 using namespace std;
  8 
  9 const int Maxn = 100010;
 10 const int Maxm = 30;
 11 int n , cnt;
 12 string s[Maxn];
 13 queue <int> Q;
 14 
 15 struct Trie {
 16     int fail;
 17     int end;
 18     int num[Maxm];
 19 } t[Maxn];
 20 
 21 struct Str {
 22     int id;
 23     int tot;
 24 } a[Maxn];
 25 
 26 inline void Clean(int x) {
 27     
 28     t[x].end = t[x].fail = 0;
 29     for(register int i=1; i<=26; i++)
 30         t[x].num[i] = 0;
 31     
 32 }
 33 
 34 inline bool comp(const Str &x , const Str &y) {
 35     if(x.tot > y.tot)    return true;
 36     if(x.tot < y.tot)    return false;
 37     return x.id < y.id;
 38 }
 39 
 40 inline void Build(string s , int idx) {
 41     
 42     register int len = s.size();
 43     register int now = 0;
 44     
 45     for(register int i=0; i<len; i++) {
 46         register int to = s[i] - 'a' + 1;
 47         if(!t[now].num[to]) {
 48             t[now].num[to] = ++ cnt;
 49             Clean(cnt);
 50         }
 51         now = t[now].num[to];
 52     }
 53     
 54     t[now].end = idx;
 55     
 56 }
 57 
 58 inline void Getfail() {
 59     
 60     while(!Q.empty())    Q.pop();
 61     
 62     for(register int i=1; i<=26; i++) {
 63         if(t[0].num[i]) {
 64             t[t[0].num[i]].fail = 0;
 65             Q.push(t[0].num[i]);
 66         }
 67     }
 68     
 69     while(!Q.empty()) {
 70         register int now = Q.front();
 71         Q.pop();
 72         for(register int i=1; i<=26; i++) {
 73             if(t[now].num[i]) {
 74                 t[t[now].num[i]].fail = t[t[now].fail].num[i];
 75                 Q.push(t[now].num[i]);
 76             } else    t[now].num[i] = t[t[now].fail].num[i];
 77         }
 78     }
 79     
 80 }
 81 
 82 inline void Query(string s) {
 83     
 84     register int len = s.size();
 85     register int now = 0;
 86     
 87     for(register int i=0; i<len; i++) {
 88         register int to = s[i] - 'a' + 1;
 89         now = t[now].num[to];
 90         for(register int j=now; j; j=t[j].fail)
 91             a[t[j].end].tot ++;
 92     }
 93     
 94 }
 95 
 96 int main() {
 97     
 98     while(scanf("%d",&n) != EOF) {
 99         
100         if(!n)    return 0;
101         
102         cnt = 0;
103         Clean(0);
104         
105         for(register int i=1; i<=n; i++) {
106             cin >> s[i];
107             a[i].id = i;
108             a[i].tot = 0;
109             Build(s[i],i);
110         }
111         
112         Getfail();
113         
114         cin >> s[0];
115         Query(s[0]);
116         
117         sort(a+1,a+n+1,comp);
118         
119         printf("%d\n",a[1].tot);
120         cout << s[a[1].id] << endl;
121         for(register int i=2; i<=n; i++) {
122             if(a[i].tot != a[i-1].tot)    break;
123             cout << s[a[i].id] << endl;
124         }
125         
126     }
127     
128     return 0;
129     
130 }

其實提升版不難,加個排序等奇奇gaygay的操做就好了QVQ

哦對了,這些字符串算法全是一個dalao講的

在這裏我要瘋狂%%%%%%%飛神

 

我能記起來的最後一個算法:

差分約束

其實這個就是個轉成SPFA的算法

利用三角形不等式,dis[i] + e[i].w < dis[j] 而後……

還有各類判環就好了啦~so~easy~

模板題:戳我

附上代碼~

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 
  5 using namespace std;
  6 
  7 typedef long long ll;
  8 const int Maxn = 100010;
  9 int n , m , tot;
 10 int repeat[Maxn];
 11 int last[Maxn];
 12 int dis[Maxn];
 13 bool vis[Maxn];
 14 
 15 struct Edge {
 16     int to;
 17     int w;
 18     int next;
 19 } e[(Maxn<<1)+Maxn];
 20 
 21 queue < int > Q;
 22 
 23 template < typename Typ >
 24 inline void read(Typ &x) {
 25     
 26     register Typ num = 0;
 27     register char ch = getchar();
 28     
 29     while(ch < '0' || ch > '9')    ch = getchar();
 30     
 31     while(ch >= '0' && ch <= '9') {
 32         num = ( num << 3 ) + ( num << 1 ) + ch - '0';
 33         ch = getchar();
 34     }
 35     
 36     x = num;
 37     
 38 }
 39 
 40 inline void add(int u , int v , int w) {
 41     tot ++;
 42     e[tot].to = v;
 43     e[tot].w = w;
 44     e[tot].next = last[u];
 45     last[u] = tot;
 46 }
 47 
 48 inline bool Spfa(int s) {
 49     
 50     while(!Q.empty())    Q.pop();
 51     vis[s] = true;
 52     Q.push(s);
 53     
 54     while(!Q.empty()) {
 55         register int u = Q.front();
 56         Q.pop();
 57         vis[u] = false;
 58         for(register int i=last[u]; i; i=e[i].next) {
 59             register int v = e[i].to;
 60             if(dis[u] + e[i].w > dis[v]) {
 61                 repeat[v] ++;
 62                 if(repeat[v] >= n)    return false;
 63                 dis[v] = dis[u] + e[i].w;
 64                 if(!vis[v]) {
 65                     vis[v] = true;
 66                     Q.push(v);
 67                 }
 68             }
 69         }
 70     }
 71     
 72     return true;
 73     
 74 }
 75 
 76 inline ll getsum() {
 77     
 78     register ll sum = 0;
 79     
 80     for(register int i=1; i<=n; i++)
 81         sum += dis[i];
 82         
 83     return sum;
 84     
 85 }
 86 
 87 int main() {
 88     
 89     read(n) , read(m);
 90     for(register int x,y,z; m--; ) {
 91         read(z) , read(x) , read(y);
 92         if(z == 1)    add(x,y,0) , add(y,x,0);
 93         if(z == 2) {
 94             if(x == y)    return !puts("-1");
 95             add(x,y,1);
 96         }
 97         if(z == 3)    add(y,x,0);
 98         if(z == 4) {
 99             if(x == y)    return !puts("-1");
100             add(y,x,1);
101         }
102         if(z == 5)    add(x,y,0);
103     }
104     
105     for(register int i=n; i>=1; i--)
106         add(0,i,1);
107     
108     register bool tmp = Spfa(0);
109     if(!tmp)    puts("-1");
110     else    printf("%lld\n",getsum());
111     
112     return 0;
113     
114 }

好了~

我以爲總結好了呢~

但是並無呢~

等到集訓結束後咱們再見面吧~

By  BlueCat

相關文章
相關標籤/搜索