A. Graph Games upsolved
\(n\) 个点,\(m\) 条边的图\((1<=n<=1e5,1<=m,q<=2e5)\) ,\(q\) 次操作,操作有两种,一种是翻转区间内边的状态,第二种是询问两个点的邻接点集是否一致 \(T\) 飞了,给每个点随机一个权值,点集的权值就是全部异或起来,冲突概率很小
对线段分块,复杂度可以达到\(O(q\sqrt m)\) (代码里快读删了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include  <bits/stdc++.h>  using  namespace  std;  const  int  N = 1e5  + 10 , M = 2e5  + 10 , sz = 510 ;  long  long  val[N], s[N], sum[sz][N];int  l[sz], r[sz], belong[M];int  u[M], v[M], lazy[sz];int  T, n, m, q, op, blk, num, x, y;  void  build ()      blk = sqrt (m);     num = 1  + (m - 1 ) / blk;     for (int  i = 1 ; i <= num; ++i) {         l[i] = (i - 1 ) * blk + 1 ;         r[i] = i * blk;         lazy[i] = 0 ;         for (int  j = 1 ; j <= n; ++j)             sum[i][j] = 0 ;     }     r[num] = m;     for (int  i = 1 ; i <= m; ++i)         belong[i] = (i - 1 ) / blk + 1 ;     for (int  i = 1 ; i <= n; ++i)         s[i] = 0 ; }   void  update (int  l, int  r)      if (belong[l] == belong[r]) {         for (int  i = l; i <= r; ++i) {             s[u[i]] ^= val[v[i]];             s[v[i]] ^= val[u[i]];         }         return ;     }     for (int  i = l; belong[i] == belong[l]; ++i) {         s[u[i]] ^= val[v[i]];         s[v[i]] ^= val[u[i]];     }     for (int  i = r; belong[i] == belong[r]; --i) {         s[u[i]] ^= val[v[i]];         s[v[i]] ^= val[u[i]];     }     for (int  i = belong[l] + 1 ; i < belong[r]; ++i)         lazy[i] ^= 1 ; }   int  main ()      srand (time (NULL ));     for (int  i = 1 ; i <= 100000 ; ++i) val[i] = 1  + rand ();     read (T);     while (T--) {         read (n); read (m);         build ();         for (int  i = 1 ; i <= m; ++i) {             read (u[i]); read (v[i]);             s[u[i]] ^= val[v[i]];             s[v[i]] ^= val[u[i]];             sum[belong[i]][u[i]] ^= val[v[i]];             sum[belong[i]][v[i]] ^= val[u[i]];         }         read (q);         while (q--) {             read (op); read (x); read (y);             if (op == 1 )                 update (x, y);             else  {                 long  long  a = s[x], b = s[y];                 for (int  i = 1 ; i <= num; ++i) if (lazy[i]) {                     a ^= sum[i][x];                     b ^= sum[i][y];                 }                 printf ("%d" , (int )(a == b));             }         }         puts ("" );     }     return  0 ; } 
B. Crazy Binary String solved at 00:16
签到
D. Big Integer upsolved 队友做的
F. Planting Trees upsolved
\(O(n^3)\) 单调队列,我是傻逼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include  <bits/stdc++.h>  using  namespace  std;const  int  N = 505 ;int  d[N][N], n, m, T, ans, mx[N], mn[N];int  minn[N], maxx[N];int  h_mn, t_mn, h_mx, t_mx;int  main ()  	scanf ("%d" , &T); 	while (T--) { 		ans = 0 ; 		scanf ("%d%d" , &n, &m); 		for (int  i = 1 ; i <= n; ++i) { 			for (int  j = 1 ; j <= n; ++j)  				scanf ("%d" , &d[i][j]); 		} 		for (int  up = 1 ; up <= n; ++up) { 			memset (mx, 0 , sizeof  			memset (mn, 0x3f , sizeof  			for (int  down = up; down <= n; ++down) { 				h_mn = t_mn = h_mx = t_mx = 0 ; 				for (int  k = 1 , left = 0 ; k <= n; ++k) { 					mx[k] = max (mx[k], d[down][k]); 					mn[k] = min (mn[k], d[down][k]); 					for (; h_mn != t_mn && mn[minn[t_mn - 1 ]] > mn[k]; ) t_mn--; 					minn[t_mn++] = k; 					for (; h_mx != t_mx && mx[maxx[t_mx - 1 ]] < mx[k]; ) t_mx--; 					maxx[t_mx++] = k; 					for (; h_mn != t_mn && h_mx != t_mx && mx[maxx[h_mx]] - mn[minn[h_mn]] > m;) { 						if (maxx[h_mx] < minn[h_mn]) 							left = maxx[h_mx++]; 						else  							left = minn[h_mn++]; 					} 					ans = max (ans, (down - up + 1 ) * (k - left)); 				} 			} 		} 		printf ("%d\n" , ans); 	} 	return  0 ; } 
G. Removing stones upsolved
等价于询问有多少个区间的区间最大值小于等于区间和
题解说是找最大值然后枚举左右两边较短的那一边的端点然后二分查另一边的端点再分治,看了别人写了个暴力枚举不合法区间的然后跑的贼快,复杂度不太会算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include  <bits/stdc++.h>  using  namespace  std;const  int  N = 3e5  + 10 ;int  a[N], T, n;long  long  ans;int  main ()  	scanf ("%d" , &T); 	while (T--) { 		ans = 0 ; 		scanf ("%d" , &n); 		for (int  i = 1 ; i <= n; ++i)  			scanf ("%d" , &a[i]); 		for (int  i = 1 ; i <= n; ++i) { 			int  l = i, r = i; 			long  long  sum = 0 ; 			while (l > 1  && sum + a[l - 1 ] < a[i]) l--, sum += a[l]; 			while (r < n && sum + a[r + 1 ] < a[i]) r++, sum += a[r]; 			ans += r - i + 1 ; 			for (int  j = l; j < i; ++j) { 				sum -= a[j]; 				while (r < n && sum + a[r + 1 ] < a[i]) r++, sum += a[r]; 				ans += r - i + 1 ; 			}  		} 		printf ("%lld\n" , 1LL  * n * (n + 1 ) / 2 - ans); 	} 	return  0 ; } 
H. Magic Line solved at 00:36
要求用一条直线把平面上的点分成两部分,两部分个数相同且不能有点在线上
注意到点的坐标范围只有\(1000\) 而你最终输出的线的坐标可以到\(1e9\) 
一定可以用一条近似竖直线的线
把点分开
upsolved
给定原序列的中位数序列(长度为\(n-2\) ),构造一个原序列
J. LRU management solved at 04:59(+22)
队友做的,他手写了一个链表。。。
用几个map维护就好了,利用map的迭代器可以自增或是自减的性质就好了
那个string可以看成一个11进制数(区分前置零)
我在贴上来的时候把快读删掉了,就是read那个函数的实现,用的是fread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 #include  <bits/stdc++.h>  using  namespace  std;const  int  N = 5e5  + 10 ;int  T, q, m, op, v;long  long  ss;char  s[12 ];map<int , long  long > ptos; map<long  long , int > stop, stov; long  long  convert (char  s[])  	long  long  val = 0 ; 	for (int  i = 0 ; s[i]; ++i) { 		val = val * 11  + s[i] - '0'  + 1 ; 	} 	return  val; } int  main ()  	read (T); 	while (T--) { 		ptos.clear (); stop.clear (); stov.clear (); 		read (q); read (m); 		ptos[100000 ] = 1e18 ; 		stop[1000000000000000000LL ] = 100000 ; 		stov[1000000000000000000LL ] = 100 ; 		while (q--) { 			read (op); read (s); read (v); 			ss = convert (s); 			if (op == 0 ) { 				if (stov.count (ss)) { 					printf ("%d\n" , stov[ss]); 					int  fi = ptos.begin ()->first; 					int  pos = stop[ss]; 					ptos.erase (ptos.find (pos)); 					stop[ss] = fi - 1 ; 					ptos[fi - 1 ] = ss; 				} 				else  { 					stov[ss] = v; 					int  fi = ptos.begin ()->first; 					stop[ss] = fi - 1 ; 					ptos[fi - 1 ] = ss; 					if (ptos.size () > m) { 						long  long  es = ptos.rbegin ()->second; 						ptos.erase (--ptos.end ()); 						stop.erase (stop.find (es)); 						stov.erase (stov.find (es)); 					} 					printf ("%d\n" , v); 				} 			} 			else  { 				if (!stov.count (ss)) { 					puts ("Invalid" ); 					continue ; 				} 				int  pos = stop[ss]; 				if (v == 0 ) { 					printf ("%d\n" , stov[ss]); 				} 				else  { 					map<int , long  long >::iterator it = ptos.find (pos); 					if (v == 1 ) { 						if (it == ptos.begin ()) { 							puts ("Invalid" ); 							continue ; 						} 						it--; 						if (stov[it->second] == 100 ) { 							puts ("Invalid" ); 							continue ; 						} 						printf ("%d\n" , stov[it->second]); 					} 					else  { 						if (++it == ptos.end ()) { 							puts ("Invalid" ); 							continue ; 						} 						if (stov[it->second] == 100 ) { 							puts ("Invalid" ); 							continue ; 						} 						printf ("%d\n" , stov[it->second]); 					} 				} 			} 		} 	} 	return  0 ; } 
用map维护string(实际上是数)到list<int>::iterator的映射似乎写起来更简单