The Preliminary Contest for ICPC China Nanchang National Invitational and International Silk-Road Programming Contest
打网络赛
比赛前的准备工作要做好
确保 c++/java/python的编译器能用
打好模板,放在桌面
A. PERFECT NUMBER PROBLEM
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e8+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 int sum[maxn]; 20 21 int main() 22 { 23 int n=100000000,i,j; 24 for (i=1;i<n;i++) 25 for (j=i;j<n;j+=i) 26 sum[j]+=i; 27 for (i=1;i<n;i++) 28 if (sum[i]==i+i) 29 printf("%d ",i); 30 return 0; 31 } 32 /* 33 6 28 496 8128 33550336 34 Process returned 0 (0x0) execution time : 24.646 s 35 */
较差的打表方法
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 20 21 int main() 22 { 23 ///我相信很大一部分同学是网上找答案的,这不好 24 // printf("6\n28\n496\n8128\n33550336"); 25 ll sum,i,j,k; 26 for (i=1;i<=1000000000;i++) 27 { 28 sum=0; 29 k=sqrt(i); 30 for (j=1;j<=k;j++) 31 if (i%j==0) 32 sum+=j+i/j; 33 if (k*k==i) 34 sum-=i; 35 sum-=i; 36 if (sum==i) 37 printf("%d ",i); 38 if (i%1000000==0) 39 printf("i=%d\n",i); 40 } 41 return 0; 42 } 43 /* 44 6 28 496 8128 33550336 45 18 min 46 */
C. Angry FFF Party
fib(x) 逐渐变得很大
而fib(fib(x))更是如此,
感觉可以打表
于是用python打表验证一下
1 import math 2 3 4 5 a=1/math.sqrt(5) 6 7 b=(1+math.sqrt(5))/2 8 9 c=(1-math.sqrt(5))/2 10 11 a 12 13 0.4472135954999579 14 15 a 16 17 for n in range(1,16): 18 19 print(n) 20 21 x=a*(pow(b,n) - pow(c,n)) 22 23 x=round(x) 24 25 print(x) 26 27 28 29 y=a*(pow(b,x) - pow(c,x)) 30 31 print(y) 32 33 print() 34 35 1 36 1 37 1.0 38 39 2 40 1 41 1.0 42 43 3 44 2 45 1.0 46 47 4 48 3 49 2.0 50 51 5 52 5 53 5.000000000000001 54 55 6 56 8 57 21.000000000000004 58 59 7 60 13 61 233.00000000000006 62 63 8 64 21 65 10946.000000000007 66 67 9 68 34 69 5702887.0000000065 70 71 10 72 55 73 139583862445.00024 74 75 11 76 89 77 1.7799794160047194e+18 78 79 12 80 144 81 5.555654042242954e+29 82 83 13 84 233 85 2.2112364063039317e+48 86 87 14 88 377 89 2.746979206949977e+78 90 91 15 92 610 93 1.3582369791278544e+127
开始用java写 BigInteger
1 import java.math.BigInteger; 2 import java.util.Scanner; 3 4 public class Main { 5 static class mat { 6 BigInteger [][]a=new BigInteger[2][2]; 7 mat() { 8 a[0][0]=a[0][1]=a[1][0]=a[1][1]=BigInteger.ZERO; 9 } 10 static mat mul(mat a,mat b) { 11 mat c=new mat(); 12 for (int k=0;k<2;k++) 13 for (int i=0;i<2;i++) 14 for (int j=0;j<2;j++) 15 c.a[i][j]=c.a[i][j].add(a.a[i][k].multiply(b.a[k][j])); 16 return c; 17 } 18 void print() { 19 for (int i=0;i<2;i++) { 20 for (int j=0;j<2;j++) 21 System.out.print(a[i][j]+" "); 22 System.out.println(); 23 } 24 System.out.println(); 25 } 26 } 27 28 static BigInteger _pow(int n) { 29 mat a=new mat(); 30 mat b=new mat(); 31 a.a[0][0]=BigInteger.ONE; 32 a.a[0][1]=BigInteger.ZERO; 33 a.a[1][0]=BigInteger.ZERO; 34 a.a[1][1]=BigInteger.ONE; 35 36 b.a[0][0]=BigInteger.ONE; 37 b.a[0][1]=BigInteger.ONE; 38 b.a[1][0]=BigInteger.ONE; 39 b.a[1][1]=BigInteger.ZERO; 40 41 while (n>0) { 42 if (n%2==1) 43 a=mat.mul(a,b); 44 b=mat.mul(b,b); 45 // b.print(); 46 n>>=1; 47 } 48 return a.a[1][0]; 49 } 50 51 public static void main(String[] args) throws Exception { 52 53 int i,len=100000;//10 54 int []a=new int[100]; 55 BigInteger []b=new BigInteger[100]; 56 StringBuffer s=new StringBuffer("1"); 57 for (i=0;i<len;i++) 58 s=s.append("0"); 59 String ss=new String(s); 60 BigInteger maxb=new BigInteger(ss); 61 // System.out.println(maxb); 62 63 // _pow(10); 64 65 a[1]=a[2]=1; 66 mat ma = new mat(); 67 for (i=1;i<100;i++) { 68 if (i<3) 69 a[i]=1; 70 else 71 a[i]=a[i-1]+a[i-2]; 72 // System.out.println(a[i]); 73 b[i]=_pow(a[i]); 74 // if (i<10) 75 // System.out.println(b[i]); 76 if (b[i].compareTo(maxb)>=0) 77 break; 78 } 79 // System.out.println("i="+i); 80 int maxg=i; 81 82 Scanner in=new Scanner(System.in); 83 int t=in.nextInt(); 84 BigInteger m; 85 86 int []num=new int[100]; 87 int g=0; 88 BigInteger[] bb=new BigInteger[11]; 89 for (i=0;i<=10;i++) 90 bb[i]=new BigInteger(Integer.toString(i)); 91 String []pr=new String[11]; 92 93 /* 94 1 1 1 2 5 21 95 */ 96 pr[1]="1"; 97 pr[2]="1 2"; 98 pr[3]="1 2 3"; 99 pr[4]="1 2 4"; 100 pr[5]="1 2 3 4"; 101 for (i=6;i<=10;i++) 102 pr[i]=pr[i-5]+" 5"; 103 104 while (t-->0) { 105 m=in.nextBigInteger(); 106 107 g=0; 108 if (m.compareTo(bb[10])>0) { 109 for (i=maxg;i>5;i--) 110 if (m.compareTo(b[i])>=0) { 111 m=m.subtract(b[i]); 112 g=g+1; 113 num[g]=i; 114 } 115 } 116 if (m.compareTo(bb[10])>0) 117 System.out.println(-1); 118 else { 119 for (i=1;i<=10;i++) 120 if (m.compareTo(bb[i])==0) 121 System.out.print(pr[i]); 122 if (m.compareTo(bb[0])!=0 && g!=0) 123 System.out.print(" "); 124 if (g==0) 125 System.out.println(); 126 for (i=g;i>=1;i--) { 127 System.out.print(num[i]); 128 if (i==1) 129 System.out.println(); 130 else 131 System.out.print(" "); 132 } 133 } 134 } 135 } 136 } 137 /* 138 1 1 1 2 5 21 139 140 1 141 1 142 1 143 2 144 5 145 21 146 233 147 10946 148 5702887 149 150 100 151 1-10 152 11 153 21 154 27 155 */
H. Coloring Game
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 const ll mod=1e9+7; 19 20 ll mul(ll a,ll b) 21 { 22 ll y=1; 23 while (b) 24 { 25 if (b&1) 26 y=y*a%mod; 27 a=a*a%mod; 28 b>>=1; 29 } 30 return y; 31 } 32 33 int main() 34 { 35 int n; 36 scanf("%d",&n); 37 if (n==1) 38 printf("1"); 39 else 40 printf("%lld",mul(3,n-2)*4%mod); 41 return 0; 42 } 43 /* 44 1000000000 45 */
K. MORE XOR
找规律
推公式较为复杂,据说用插板法
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <set> #include <map> #include <queue> #include <iostream> using namespace std; #define ll long long const int maxn=1e5+10; const int inf=1e9; const double eps=1e-8; int f[4][maxn],a[maxn]; int main() { // printf("%d",1^2^5^6^9^10); int T,n,q,i,j,k,x,y,s,t,v; scanf("%d",&T); while (T--) { scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]); for (k=0;k<4;k++) for (i=(k==0)?4:k,j=1;i<=n;i+=4,j++) f[k][j]=f[k][j-1]^a[i]; scanf("%d",&q); while (q--) { scanf("%d%d",&i,&j); y=(j-i+1)%4; if (y==1) { ///i,i+4,i+8 ... x=i%4; s=(i+3)/4; t=s+(j-i)/4; printf("%d\n",f[x][t]^f[x][s-1]); } else if (y==2) { x=i%4; s=(i+3)/4; t=s+(j-i)/4; v=f[x][t]^f[x][s-1]; i++; x=i%4; s=(i+3)/4; t=s+(j-i)/4; printf("%d\n",v^f[x][t]^f[x][s-1]); } else if (y==3) { i++; x=i%4; s=(i+3)/4; t=s+(j-i)/4; printf("%d\n",f[x][t]^f[x][s-1]); } else printf("0\n"); } } return 0; } /* 1 10 1 2 3 4 5 6 7 8 9 10 100 1 7 */
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 int n=10; 20 21 struct node 22 { 23 int a[30]; 24 node operator+(const node &y) 25 { 26 node z; 27 for (int i=1;i<=n;i++) 28 z.a[i]=a[i]+y.a[i]; 29 return z; 30 } 31 }f[4][30][30]; 32 33 int main() 34 { 35 int i,j,k,l; 36 int x=3; 37 for (i=1;i<=n;i++) 38 f[0][i][i].a[i]=1; 39 for (l=1;l<=x;l++) 40 { 41 // for (i=1;i<n;i++) 42 // { 43 // f[l][i][i]=f[l-1][i][i]; 44 // for (j=i+1;j<=n;j++) 45 // f[l][i][j]=f[l][i][j-1]+f[l-1][j][j]; 46 // } 47 48 for (i=1;i<=n;i++) 49 for (j=i;j<=n;j++) 50 { 51 if (i!=j) 52 f[l][i][j]=f[l][i][j-1]; 53 for (k=i;k<=j;k++) 54 f[l][i][j]=f[l][i][j]+f[l-1][k][j]; 55 } 56 } 57 int y=3; 58 for (i=1;i<=n;i++) 59 { 60 for (j=1;j<=n;j++) 61 // printf("%d%c",f[y][1][i].a[j],j==n?'\n':' '); 62 printf("%d%c",f[y][1][i].a[j] &1,j==n?'\n':' '); 63 } 64 return 0; 65 } 66 /* 67 1 0 0 0 0 0 0 0 0 0 68 1 1 0 0 0 0 0 0 0 0 69 0 1 0 0 0 0 0 0 0 0 70 0 0 0 0 0 0 0 0 0 0 71 1 0 0 0 1 0 0 0 0 0 72 1 1 0 0 1 1 0 0 0 0 73 0 1 0 0 0 1 0 0 0 0 74 0 0 0 0 0 0 0 0 0 0 75 1 0 0 0 1 0 0 0 1 0 76 1 1 0 0 1 1 0 0 1 1 77 78 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 87 1 1 0 0 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 88 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 91 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 0 0 0 92 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 95 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 96 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 98 */
M. Subsequence
序列自动机
非正统的写法:
1.从后往前,记录每一个字符最新出现的位置
2.贪心,找到第一个字符,在第一个字符位置之后找第二个字符,...
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e5+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 int f[maxn][128],pre[maxn]; 20 char s[maxn]; 21 22 int main() 23 { 24 int i,j,len,t; 25 memset(pre,0xff,sizeof(pre)); 26 s[0]='a'; 27 scanf("%s",s+1); 28 len=strlen(s+1); 29 for (i=len;i>=0;i--) 30 { 31 for (j=0;j<128;j++) 32 f[i][j]=pre[j]; 33 pre[s[i]]=i; 34 } 35 scanf("%d",&t); 36 while (t--) 37 { 38 scanf("%s",s); 39 len=strlen(s); 40 j=f[0][s[0]]; 41 for (i=1;i<len;i++) 42 { 43 if (j==-1) 44 break; 45 j=f[j][s[i]]; 46 } 47 if (j!=-1) 48 printf("YES\n"); 49 else 50 printf("NO\n"); 51 } 52 return 0; 53 } 54 /* 55 56 */
C. Angry FFF Party
数位dp
原来的数据是完全无用的,
只需要火柴棒总数保持一致,
只需要对于每一位,火柴棒加的次数完全一样
不用考虑前导0
+0 -> +9
-0 -> +5
w为数字的位数,y使用的火柴数
f[w][y] 的最大值
f[w][y]=max(f[w-1][y-g[i]]+i*10^(w-1)) i=0..9
w<10,y<w*7+2
-11..1 无法改变
f[1][3]=-1
f[p][p*2+1]=-11..1
其它时候不用减法(至少可以节省一根火柴,使负号变为加号)
这个不成立,在第一个数时(潜在加法)
预处理
对于当前的前x个数字,y为使用的火柴棒总数,以此最大的值
对于第x个数字,位数为w
a[x][y]=max(a[x-1][z]+f[w][z-y])
x<=50,y<=7*50+2*49=448
[49个加号,50个数]
易错点:
+/- 不能单独每一位,而要整体求
正确通过 | 2019-04-21 00:57 | 5ms | 448kB | c++14 |
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <set> 8 #include <map> 9 #include <queue> 10 #include <iostream> 11 using namespace std; 12 13 #define ll long long 14 15 const int maxn=1e4+10; 16 const int inf=1e9; 17 const double eps=1e-8; 18 19 /** 20 其实最多只有9位, 21 是小于10^9,没有等于 22 23 999999999+999999999+... 24 超过int 25 **/ 26 27 int g[10]={6,2,5,5,4,5,6,3,7,6}; 28 int f[12][100]; 29 int mul[12]; 30 ll a[51][500]; 31 int fv[12]; 32 int add[128]; 33 char s[110]; 34 35 int main() 36 { 37 bool vis; 38 int i,j,k,l,maxw,w,t,n,tot,sum,c; 39 40 // printf("%d\n",'+');///43 41 // printf("%d\n",'-');///45 42 add[43]=2,add[45]=1; 43 for (i=48;i<48+10;i++) 44 add[i]=g[i-48]; 45 46 mul[1]=1; 47 for (i=2;i<=9;i++) 48 mul[i]=mul[i-1]*10; 49 50 fv[1]=-1; 51 for (i=2;i<=9;i++) 52 fv[i]=fv[i-1]*10-1; 53 54 memset(f,0x8f,sizeof(f)); 55 f[0][2]=0;///+ 56 for (i=1;i<=10;i++) 57 { 58 maxw=(i-1)*7+2; 59 for (j=0;j<=maxw;j++) 60 for (l=0;l<=9;l++) ///或者只要用火柴数在一个数量时最大的数即可 61 f[i][j+g[l]]=max(f[i][j+g[l]],f[i-1][j]+l*mul[i]); 62 } 63 64 scanf("%d",&t); 65 while (t--) 66 { 67 memset(a,0x8f,sizeof(a)); 68 scanf("%d",&n); 69 scanf("%s",s); 70 tot=0; 71 vis=0; 72 sum=0; 73 a[0][0]=0; 74 i=0; 75 c=0; 76 for (w=0;w<=n;w++) 77 { 78 tot+=add[s[w]]; 79 if (s[w]=='+' || s[w]=='-' || w==n) 80 { 81 c++; 82 maxw=i*7+2; 83 for (j=0;j<=sum;j++) 84 for (k=0;k<=maxw;k++) 85 ///f[i][k](int memset)相比a[j](ll memset)小很多,减很多次,仍不会到达下界 86 a[c][j+k]=max(a[c][j+k],a[c-1][j]+f[i][k]); ///可以使用滚动数组 87 88 if (vis) 89 for (j=0;j<=sum;j++) 90 a[c][j+2*i+1]=max(a[c][j+2*i+1],a[c-1][j]+fv[i]); 91 92 sum+=maxw; ///当然也可以求出tot后再求 93 vis=1; 94 i=0; 95 continue; 96 } 97 else 98 i++; 99 } 100 printf("%lld\n",a[c][tot+2]); ///第一个加号是没有的 101 } 102 return 0; 103 } 104 /* 105 10 106 11 107 100000000+9 108 13 109 111-111111-11 110 20 111 100000000-99999999+1 112 36 113 10000000+12345+0+1+2+3+4+5+6+7+8+9 114 115 */
I. Max answer
单调栈+线段树
单调栈
找到一个数左边/右边的第一个大于其的数
把数列出来,容易找到方法
7 8 9 5(则9 8 7 出栈并赋值)
线段树
[l,r]区间 数为d 包含d的最大区间
sum[query_max(d,r)] - sum[query_min(l,d-1)]
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <set> 7 #include <map> 8 #include <list> 9 #include <queue> 10 #include <vector> 11 #include <bitset> 12 #include <algorithm> 13 #include <iostream> 14 using namespace std; 15 #define ll long long 16 17 const double eps=1e-8; 18 const int maxn=5e5+10; 19 const ll inf=1e18; 20 21 22 int a[maxn],lef[maxn],rig[maxn],st[maxn],maxnum[maxn<<2],minnum[maxn<<2]; 23 ll sum[maxn]; 24 25 void build(int ind,int l,int r) 26 { 27 if (l==r) 28 maxnum[ind]=minnum[ind]=l; 29 else 30 { 31 int m=(l+r)>>1; 32 build(ind<<1,l,m); 33 build(ind<<1|1,m+1,r); 34 if (sum[ maxnum[ind<<1] ] > sum[ maxnum[ind<<1|1] ]) 35 maxnum[ind]=maxnum[ind<<1]; 36 else 37 maxnum[ind]=maxnum[ind<<1|1]; 38 39 if (sum[ minnum[ind<<1] ] < sum[ minnum[ind<<1|1] ]) 40 minnum[ind]=minnum[ind<<1]; 41 else 42 minnum[ind]=minnum[ind<<1|1]; 43 } 44 } 45 46 int query_max(int ind,int l,int r,int x,int y) 47 { 48 if (x>y) 49 return 0; 50 if (x<=l && r<=y) 51 return maxnum[ind]; 52 int m=(l+r)>>1,b=-1; 53 if (x<=m) 54 b=query_max(ind<<1,l,m,x,y); 55 if (m<y) 56 { 57 if (b==-1) 58 return query_max(ind<<1|1,m+1,r,x,y); 59 else 60 { 61 int c=query_max(ind<<1|1,m+1,r,x,y); 62 if (sum[b]>sum[c]) 63 return b; 64 return c; 65 } 66 } 67 return b; /// 68 } 69 70 int query_min(int ind,int l,int r,int x,int y) 71 { 72 if (x>y) 73 return 0; 74 if (x<=l && r<=y) 75 return minnum[ind]; 76 int m=(l+r)>>1,b=-1; 77 if (x<=m) 78 b=query_min(ind<<1,l,m,x,y); 79 if (m<y) 80 { 81 if (b==-1) 82 return query_min(ind<<1|1,m+1,r,x,y); 83 else 84 { 85 int c=query_min(ind<<1|1,m+1,r,x,y); 86 if (sum[b]<sum[c]) 87 return b; 88 return c; 89 } 90 } 91 return b; /// 92 } 93 94 int main() 95 { 96 int n,i,g; 97 ll r; 98 scanf("%d",&n); 99 for (i=1;i<=n;i++) 100 scanf("%d",&a[i]); 101 102 g=0; 103 for (i=1;i<=n;i++) 104 { 105 while (g>0 && a[st[g]]>a[i]) 106 { 107 rig[st[g]]=i; 108 g--; 109 } 110 st[++g]=i; 111 sum[i]=sum[i-1]+a[i]; 112 } 113 114 g=0; 115 for (i=n;i>=1;i--) 116 { 117 while (g>0 && a[st[g]]>a[i]) 118 { 119 lef[st[g]]=i; 120 g--; 121 } 122 st[++g]=i; 123 } 124 125 build(1,1,n); 126 r=-inf; 127 for (i=1;i<=n;i++) 128 { 129 if (rig[i]==0) 130 rig[i]=n+1; 131 if (a[i]>=0) 132 r=max(r,a[i]*(sum[rig[i]-1]-sum[lef[i]])); 133 else 134 r=max(r,a[i]*(sum[query_min(1,1,n,i,rig[i]-1)]-max(0ll,sum[query_max(1,1,n,lef[i]+1,i-1)])));///< 135 } 136 printf("%lld",r); 137 return 0; 138 } 139 /* 140 5 141 -2 1 -3 -4 3 142 143 6 144 -1 -2 -3 -4 -5 -6 145 146 3 147 -1 -3 -2 148 149 150 1 151 -3 152 */
J. Distance on the tree
1.树剖
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 #define ll long long 10 const double eps=1e-8; 11 const int maxn=1e5+10; 12 13 ///°´ÕձߵĴóСÅÅÐò 14 ///树剖: 边 而不是 点 15 16 struct node 17 { 18 int d; 19 node *to; 20 }*e[maxn]; 21 22 struct rec 23 { 24 int u,v,w,num,mode; 25 bool operator<(const rec &y) const 26 { 27 if (w==y.w) 28 return mode<y.mode; 29 return w<y.w; 30 } 31 }b[maxn+maxn]; 32 33 int sum[maxn]; 34 35 int fa[maxn],dep[maxn],siz[maxn],son[maxn]; 36 int id[maxn],top[maxn]; 37 int n,num; 38 bool vis[maxn]; 39 int tr[maxn<<2]; 40 41 void dfs1(int d) 42 { 43 int dd; 44 node* p=e[d]; 45 vis[d]=1; 46 siz[d]=1; 47 while (p) 48 { 49 dd=p->d; 50 if (!vis[dd]) 51 { 52 fa[dd]=d; 53 dep[dd]=dep[d]+1; 54 dfs1(dd); 55 siz[d]+=siz[dd]; 56 if (siz[dd]>siz[son[d]]) 57 son[d]=dd; 58 } 59 p=p->to; 60 } 61 } 62 63 void dfs2(int d,int topd) 64 { 65 id[d]=++num; 66 top[d]=topd; 67 if (son[d]!=0) 68 { 69 int dd; 70 node *p; 71 dfs2(son[d],topd); 72 73 p=e[d]; 74 while (p) 75 { 76 dd=p->d; 77 if (dd!=son[d] && dd!=fa[d]) 78 dfs2(dd,dd); 79 p=p->to; 80 } 81 } 82 } 83 84 void update(int ind,int l,int r,int x) 85 { 86 tr[ind]++; 87 if (l==r) 88 return; 89 int m=(l+r)>>1; 90 if (x<=m) 91 update(ind<<1,l,m,x); 92 else 93 update(ind<<1|1,m+1,r,x); 94 } 95 96 int query(int ind,int l,int r,int x,int y) 97 { 98 if (x<=l && r<=y) 99 return tr[ind]; 100 int m=(l+r)>>1,sum=0; 101 if (x<=m) 102 sum+=query(ind<<1,l,m,x,y); 103 if (m<y) 104 sum+=query(ind<<1|1,m+1,r,x,y); 105 return sum; 106 } 107 108 int cal(int x,int y) 109 { 110 int sum=0; 111 while (top[x]!=top[y]) 112 { 113 if (dep[top[x]]<dep[top[y]]) 114 swap(x,y); 115 sum+=query(1,1,n,id[top[x]],id[x]); 116 x=fa[top[x]]; 117 } 118 119 if (dep[x]<dep[y]) 120 swap(x,y); 121 ///u,v not the same 122 ///减去根节点 123 return sum+query(1,1,n,id[y]+1,id[x]); 124 } 125 126 int main() 127 { 128 node *p; 129 int m,i,u,v; 130 scanf("%d%d",&n,&m); 131 for (i=1;i<n;i++) 132 { 133 scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w); 134 b[i].num=i; 135 b[i].mode=0; 136 137 p=new node(); 138 p->d=b[i].v; 139 p->to=e[b[i].u]; 140 e[b[i].u]=p; 141 142 p=new node(); 143 p->d=b[i].u; 144 p->to=e[b[i].v]; 145 e[b[i].v]=p; 146 } 147 for (i=n;i<n+m;i++) 148 { 149 scanf("%d%d%d",&b[i].u,&b[i].v,&b[i].w); 150 b[i].num=i; 151 b[i].mode=1; 152 } 153 sort(b+1,b+n+m); 154 155 fa[1]=1; 156 dfs1(1); 157 158 dfs2(1,1); 159 160 for (i=1;i<n+m;i++) 161 { 162 u=b[i].u; 163 v=b[i].v; 164 if (dep[u]<dep[v]) 165 swap(u,v); 166 167 ///往距离远的点加值 168 if (b[i].num<n) 169 update(1,1,n,id[u]); 170 else 171 sum[b[i].num-n+1]=cal(u,v); 172 } 173 174 for (i=1;i<=m;i++) 175 printf("%d\n",sum[i]); 176 return 0; 177 }
2.主席树
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 10 #define ll long long 11 const double eps=1e-8; 12 const int maxn=1e5+10; 13 const int maxv=1e9; 14 15 ///1-i中的所有数 1-fa(j) -> 1-j 链 主席树 16 17 struct node 18 { 19 int d,len,num; 20 node *to; 21 node *opp; 22 int c; 23 }*e[maxn],*point[maxn]; 24 25 struct rec 26 {///any d,dd 经历两次 可以选择d中加入编号比其大的 27 int l,r,sum; 28 }tr[maxn*50]; 29 30 int sum[maxn],fa[maxn],be[maxn],num; 31 bool vis[maxn]; 32 33 void build(int ind_old,int ind,int l,int r,int x) 34 { 35 if (l==r) ///single 36 { 37 tr[ind].sum=tr[ind_old].sum+1; 38 return; 39 } 40 int m=(l+r)>>1; 41 if (x<=m) 42 { 43 tr[ind].r=tr[ind_old].r; 44 tr[ind].l=++num; 45 build(tr[ind_old].l,tr[ind].l,l,m,x); 46 } 47 else 48 { 49 tr[ind].l=tr[ind_old].l; 50 tr[ind].r=++num; 51 build(tr[ind_old].r,tr[ind].r,m+1,r,x); 52 } 53 tr[ind].sum=tr[tr[ind].l].sum + tr[tr[ind].r].sum; 54 } 55 56 int query(int ind,int l,int r,int k) ///[1,k] 57 { 58 if (r<=k) 59 return tr[ind].sum; 60 int m=(l+r)>>1,sum=0; 61 if (tr[ind].l!=0) ///存在(该点在线段树中被创建) 62 sum+=query(tr[ind].l,l,m,k); 63 if (m<k && tr[ind].r!=0) 64 sum+=query(tr[ind].r,m+1,r,k); 65 return sum; 66 } 67 68 void dfs(int d) 69 { 70 node *p=e[d]; 71 int dd; 72 vis[d]=1; 73 while (p) 74 { 75 dd=p->d; 76 if (!vis[dd]) 77 { 78 be[dd]=++num; 79 build(be[d],be[dd],1,maxv,p->len); 80 dfs(dd); 81 } 82 p=p->to; 83 } 84 } 85 86 int getf(int d) 87 { 88 if (fa[d]==d) 89 return d; 90 fa[d]=getf(fa[d]); 91 return fa[d]; 92 } 93 94 void lca(int d) 95 { 96 int dd,x,y; 97 node *p=e[d]; 98 vis[d]=1; 99 while (p) 100 { 101 dd=p->d; 102 if (!vis[dd]) 103 { 104 lca(dd); 105 x=getf(d); 106 y=getf(dd); 107 fa[y]=x; 108 } 109 p=p->to; 110 } 111 112 p=point[d]; 113 while (p) 114 { 115 dd=p->d; 116 ///也许出现一次,也许出现两次 117 if (vis[dd] && p->opp->c==0) 118 { 119 sum[p->num]-=query(be[getf(dd)],1,maxv,p->len)*2; 120 p->c=1; 121 } 122 123 p=p->to; 124 } 125 } 126 127 int main() 128 { 129 node *p,*pp; 130 int n,m,u,v,w,k,i; 131 scanf("%d%d",&n,&m); 132 for (i=1;i<=n;i++) 133 fa[i]=i; 134 135 for (i=1;i<n;i++) 136 { 137 scanf("%d%d%d",&u,&v,&w); 138 139 p=new node(); 140 p->d=v; 141 p->len=w; 142 p->to=e[u]; 143 e[u]=p; 144 145 p=new node(); 146 p->d=u; 147 p->len=w; 148 p->to=e[v]; 149 e[v]=p; 150 } 151 152 num=1; 153 be[1]=1; 154 155 dfs(1); 156 157 for (i=1;i<=m;i++) 158 { 159 scanf("%d%d%d",&u,&v,&k); 160 161 p=new node(); 162 pp=new node(); 163 164 p->d=v; 165 p->len=k; 166 p->num=i; 167 p->to=point[u]; 168 p->opp=pp; 169 p->c=0; 170 point[u]=p; 171 172 pp->d=u; 173 pp->len=k; 174 pp->num=i; 175 pp->to=point[v]; 176 pp->opp=p; 177 pp->c=0; 178 point[v]=pp; 179 180 sum[i]=query(be[u],1,maxv,k) + query(be[v],1,maxv,k); 181 182 // printf("%d %d\n",query(be[u],1,maxv,k),query(be[v],1,maxv,k)); 183 } 184 185 memset(vis,0,sizeof(vis)); 186 lca(1); 187 188 for (i=1;i<=m;i++) 189 printf("%d\n",sum[i]); 190 return 0; 191 }