Codeforce 219 div1

B

  4D"部分和"问题,相当于2D部分和的拓展,我是分解成2D部分和做的:

  f[x1][y1][x2][y2]=true/false 表示 左上(x1,y1) 右下(x2,y2)的矩形是否是good rectangle;

  p1[][]x][y]表示右下为(x,y)的good rectangle有多少个,相当于一个[x][y]确定的2D前缀和;

  t[i][j][x][y]表示左上在矩形 (i,j) (x,y) 区域内 右下确定为(x,y)的方案数有多少个,可以o(1)计算:

  t[i][j][x][y]=p1[x][y][x][y]-

         p1[i-1][y][x][y]-

         p1[x][j-1][x][y]+

         p1[i-1][j-1][x][y];

  p2[x1][y1][x2][y2] 表示询问(x1,y1) (x2,y2) , 它恰好就是t[x1][y1][][] 在(x1,y1)确定下的2D前缀和.

  

 1 void init()

 2 {

 3     for (int i=1 ; i<=n ; i++ )

 4     for (int j=1 ; j<=m ; j++ ) sum[i][j]=s[i][j]=='1'?1:0;

 5     for (int i=1 ; i<=n ; i++ )

 6     for (int j=1 ; j<=m ; j++ ) sum[i][j]=sum[i][j-1]+sum[i][j];

 7     for (int i=1 ; i<=m ; i++ )

 8     for (int j=1 ; j<=n ; j++ ) sum[j][i]=sum[j-1][i]+sum[j][i];

 9 

10     for (int x=1 ; x<=n ; x++ )

11     for (int y=1 ; y<=m ; y++ )

12     for (int i=1 ; i<=x ; i++ )

13     for (int j=1 ; j<=y ; j++ )

14         if (check(i,j,x,y)) f[i][j][x][y]=1;

15 

16     for (int x=1 ; x<=n ; x++ )

17     for (int y=1 ; y<=m ; y++ )

18     {

19         for (int i=1 ; i<=x ; i++ )

20         for (int j=1 ; j<=y ; j++ )

21             p1[i][j][x][y] = p1[i][j-1][x][y]+f[i][j][x][y];

22         for (int i=1 ; i<=y ; i++ )

23         for (int j=1 ; j<=x ; j++ )

24             p1[j][i][x][y] = p1[j-1][i][x][y]+p1[j][i][x][y];

25     }

26     for (int x=1 ; x<=n ; x++ )

27     for (int y=1 ; y<=m ; y++ )

28     {

29         for (int i=x ; i<=n ; i++ )

30         for (int j=y ; j<=m ; j++ )

31             p2[x][y][i][j] = p2[x][y][i][j-1] + getvar(x,y,i,j);

32         for (int i=y ; i<=m ; i++ )

33         for (int j=x ; j<=n ; j++ )

34             p2[x][y][j][i] = p2[x][y][j-1][i] + p2[x][y][j][i];

35     }

36 }
View Code

 

C

  题目描述有点绕啊,原来d是最多单位时间走d步的意思, 不是每步走d...

  总之最后问题转化成区间最值问题,好在询问区间每次只有头尾不同,可以用单调队列优化.

D

  解决问题的关键是插入或删除一个点的同时维护连通块大小.

  先考虑一个静态的问题:对于给定的集合求size.

  如果按dfs序考虑,ans*2 = sigma(dist(order,order+1)) + dist(first,end)。

  现在动态考虑,如果插入的点i在u,v中间:

    add = dist(u,i) + dist(i,v) - dist(u,v)

  可以理解为,新增的代价是连接u,i的代价+连接i,v的代价,但要此前u,v已经连接了,所以要减去加入前连接(u,v)的代价.

  另外两种可能是:

  u不存在和v不存在,那么add = dist(*,i)  ( *表示u或者v);

  删除可以类似考虑.

  最后,问题转化为,动态求集合中比order[i]小的最大值和比order[i]大的最小值,用set或者树状数组都可以解决.

  

  1 #define maxn 100010

  2 vector<int>e[maxn];

  3 int n,k,sz,dep[maxn],bit[maxn<<1|1],

  4 first[maxn],rmq[25][maxn<<1|1],t;

  5 

  6 void dfs(int cur,int fa)

  7 {

  8     rmq[0][++t]=cur;

  9     first[cur]=t;

 10     rep(i,(int)e[cur].size()) if(e[cur][i]!=fa)

 11     {

 12         dep[e[cur][i]]=dep[cur]+1;

 13         dfs(e[cur][i],cur);

 14         rmq[0][++t]=cur;

 15     }

 16 }

 17 void initrmq()

 18 {

 19     for (int i=1 ; (1<<i)<=t ; i++ )

 20     for (int j=1 ; j+(1<<i)-1<=t ; j++ )

 21     {

 22         int a=rmq[i-1][j];

 23         int b=rmq[i-1][j+(1<<(i-1))];

 24         if (dep[a]<dep[b]) rmq[i][j]=a;

 25         else rmq[i][j]=b;

 26     }

 27 }

 28 int lca(int a,int b)

 29 {

 30     assert(a && b);

 31     int l,r,len=0;

 32     l = min(first[a],first[b]);

 33     r = max(first[a],first[b]);

 34     while (1<<(len+1)<=(r-l+1)) len++;

 35     if (dep[rmq[len][l]]<dep[rmq[len][r-(1<<len)+1]])

 36         return rmq[len][l];

 37     else return rmq[len][r-(1<<len)+1];

 38 }

 39 int lowbit(int x) {return x&(-x);}

 40 void ins(int x,int var)

 41 {

 42     for (int i=x ; i<=t ; i+=lowbit(i)) bit[i]+=var;

 43 }

 44 int query(int x)

 45 {

 46     int res=0;

 47     for (int i=x ; i>0 ; i-=lowbit(i)) res+=bit[i];

 48     return res;

 49 }

 50 int range_sum(int l,int r){return query(r)-query(l-1);}

 51 int binsearchr(int l,int r)

 52 {

 53     while (l<=r)

 54     {

 55         if (range_sum(mid,r)) l=mid;

 56         else r=mid-1;

 57         if (l+1>=r)

 58         {

 59             if (range_sum(r,r)) return r;

 60             if (range_sum(l,l)) return l;

 61             return 0;

 62         }

 63     }

 64     return 0;

 65 }

 66 int binsearchl(int l,int r)

 67 {

 68     while (l<=r)

 69     {

 70         if (range_sum(l,mid)) r=mid;

 71         else l=mid+1;

 72         if (l+1>=r)

 73         {

 74             if (range_sum(l,l)) return l;

 75             if (range_sum(r,r)) return r;

 76             return 0;

 77         }

 78     }

 79     return 0;

 80 }

 81 int getdist(int u,int v) { return dep[u]+dep[v]-2*dep[lca(u,v)]; }

 82 int getsize()

 83 {

 84     int l = rmq[0][binsearchl(1,t)];

 85     int r = rmq[0][binsearchr(1,t)];

 86     assert(l && r);

 87     int v = getdist(l,r);

 88     return sz + v;

 89 }

 90 void add(int x)

 91 {

 92     int dfst = first[x];

 93     int l = rmq[0][binsearchr(1,dfst-1)];

 94     int r = rmq[0][binsearchl(dfst+1,t)];

 95     int v = 0;

 96     if (l) v += getdist(x,l);

 97     if (r) v += getdist(x,r);

 98     if (l && r) v -= getdist(l,r);

 99     sz += v;

100     ins(dfst,1);

101 }

102 void del(int x)

103 {

104     int dfst = first[x];

105     int l = rmq[0][binsearchr(1,dfst-1)];

106     int r = rmq[0][binsearchl(dfst+1,t)];

107     int v = 0;

108     if (l) v += getdist(x,l);

109     if (r) v += getdist(x,r);

110     if (l && r) v -= getdist(l,r);

111     sz -= v;

112     ins(dfst,-1);

113 

114 }

115 int main()

116 {

117 //    freopen("test.txt","r",stdin);

118     scanf("%d%d",&n,&k);

119     for (int i=1 ; i<n ; i++ )

120     {

121         int u,v;

122         scanf("%d%d",&u,&v);

123         e[u].push_back(v);

124         e[v].push_back(u);

125     }

126     dfs(1,0);

127     initrmq();

128     int ans=1;

129     for (int l=1,i=1 ; i<=n ; i++ )

130     {

131         add(i);

132         while (getsize()>(k-1)*2) del(l++);

133         ans = max(i-l+1,ans);

134     }

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

136     return 0;

137 }
View Code

 E

  (反演。。。不会T-T)

  

你可能感兴趣的:(code)