Codeforces Round #394 (Div. 2) F. Dasha and Photos (Binary Prefixes and + Segment Tree, Good Question)

Keywords: REST ascii

Title Link
F. Dasha and Photos
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Dasha decided to have a rest after solving the problem D and began to look photos from previous competitions.

Let's call photos as the matrix with the size n × m, which consists of lowercase English letters.

Some k photos especially interested her, because they can be received from photo-template by painting a rectangular area in a certain color. Let's call such photos special. 

More formally the i-th special photo is received from the photo-template by replacing all characters on some rectangle with upper left corner of the cell with coordinates (ai, bi) and lower right corner in the cell with coordinates (ci, di) to the symbol ei.

Dasha asks you to find the special photo so that the total distance from it to all other special photos is minimum. And calculate this distance.

Determine the distance between two photos as the sum of distances between all corresponding letters. The distance between two letters is the difference module of their positions in the alphabet. For example, the distance between letters 'h' and 'm' equals |8 - 13| = 5, because the letter 'h' is the 8-th in the alphabet, the letter 'm' is the 13-th.

Input

The first line contains three integers n, m, k (1 ≤ n, m ≤ 103, 1 ≤ k ≤ 3·105) — the number of strings in the photo-template, the number of columns and the number of special photos which are interesting for Dasha. 

The next n lines contains the string with m length which consists of little Latin characters — the description of the photo-template.

Each of the next k lines contains the description of the special photo in the following format, "ai bi ci di ei" (1 ≤ ai ≤ ci ≤ n, 1 ≤ bi ≤ di ≤ m), where (ai, bi) — is the coordinate of the upper left corner of the rectangle, (ci, di) — is the description of the lower right corner, and ei — is the little Latin letter which replaces the photo-template in the described rectangle. 

Output

In the only line print the minimum total distance from the found special photo to all other special photos.

Examples
input
3 3 2
aaa
aaa
aaa
1 1 2 2 b
2 2 3 3 c
output
10
input
5 5 3
abcde
eabcd
deabc
cdeab
bcdea
1 1 3 4 f
1 2 3 3 e
1 3 3 4 i
output
59
Note

In the first example the photos are following: 

bba    aaa
bba    acc
aaa    acc

The distance between them is 10.



Title:

Give you an alphabetic matrix of n * m n * m, and then give you kk independent operations, each operation is to cover a subrectangle of the original matrix with a given character.

A new matrix after operation is called a special matrix.

Defining the difference between two matrices is the sum of absolute difference values of the corresponding letter ASCII codes

Find a special matrix to minimize the sum of the difference values between it and the remaining k_1k_1 special matrix.

Output Minimum



Reference blog

Explanation:

n*m is not big, so you can try to preprocess the answer for each character.

Firstly, k matrices are inserted and deleted at line a and C. Because the covering part is a rectangle, the column corresponds to an interval.

Method 1:

For each row, column [1,m] is an interval. To insert or delete the row is to add or subtract the interval. When calculating the answer of each point, we first make a single point query in the 26 line segment tree, find out the number of occurrences of each character at this point in this k operation, and take out the answer corresponding to each letter (note that some matrices do not cover the current point, we need to count the letters of the original matrix). Then enumerate the filled letters and calculate them directly.  
Next is the statistical answer: to fill in each letter, the original matrix has been found out each answer, do a two-dimensional prefix sum, and then enumerate k matrices, subtract the answer covering the rectangle on the answer of the original matrix, and then fill in the answer of the corresponding letter, and get the answer of the matrix.

Time complexity O(26nmlogm) can pass through all data.

Note that there is a special application of line segment tree here. Because the line segment tree in this question is an interval update and a single point query, it does not need lazy tag, as long as the query path from the root node to the query point, plus the weights of the nodes passing through the path.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define mp make_pair
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll inf=0x3fffffffffffff;
const ll mod=1000000007;
const int maxn=1e3+100;
struct node
{
    int x1,y1,x2,y2,kind;
}a[maxn*300];
int seg[30][maxn*4];  //26 segment trees, recording 26 characters
char map[maxn][maxn];
VI in[maxn],out[maxn];
int cnt[30];
ll p[maxn][maxn],s[30][maxn][maxn];  //Two Binary Prefixes and Sums
void update(int i,int l,int r,int L,int R,int *t,int v) //Interval update
{
    if(L==l&&R==r)
    {
        t[i]+=v;
        return;
    }
    int m=(L+R)/2;
    if(r<=m) update(i*2,l,r,L,m,t,v);
    else if(l>m) update(i*2+1,l,r,m+1,R,t,v);
    else
    {
        update(i*2,l,m,L,m,t,v);
        update(i*2+1,m+1,r,m+1,R,t,v);
    }
}
int query(int i,int pos,int L,int R,int *t)
{
    if(L==R)
        return t[i];
    int m=(L+R)/2;
    if(pos<=m) return t[i]+query(i*2,pos,L,m,t);  //It is not necessary to use lazy marker for single point query after interval updating. It is only necessary to add the weights of all points along the path from the root to this point of the online segment tree.
    else return t[i]+query(i*2+1,pos,m+1,R,t);
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    rep(i,1,n+1) scanf("%s",map[i]+1);
    rep(i,0,k)
    {
        scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
        in[a[i].x1].pb(i),out[a[i].x2].pb(i);
        char str[10];
        scanf("%s",str);
        a[i].kind=str[0]-'a';
    }
    
    rep(i,1,n+1)
    {
        vector<int>::iterator it;
        for(it=in[i].begin();it!=in[i].end();it++)
        {
            update(1,a[*it].y1,a[*it].y2,1,m,seg[a[*it].kind],1);
        }
        rep(j,1,m+1)
        {
            int num=0;
            ll sum=0;
            memset(cnt,0,sizeof(cnt));
            rep(x,0,26)
            {
                cnt[x]+=query(1,j,1,m,seg[x]);
                num+=cnt[x];
                sum+=cnt[x]*x;
            }
            cnt[map[i][j]-'a']+=k-num;
            sum+=(map[i][j]-'a')*(k-num);
            rep(x,0,26)
            {
                if(x==map[i][j]-'a')
                    p[i][j]=p[i-1][j]+p[i][j-1]-p[i-1][j-1]+sum; //Sum of the difference values of the other k sub-matrices (1,1)-(i,j) recorded by p[i][j]
                s[x][i][j]=s[x][i-1][j]+s[x][i][j-1]-s[x][i-1][j-1]+sum; //s[x][i][j] denotes the sum of the differences between the sub-matrices (1,1)-(i,j) and the other k after filling in the characters'a'+x
                if(x>0) cnt[x]+=cnt[x-1];
                sum+=cnt[x]-(k-cnt[x]);   //Sum is the sum of the difference between point (i,j) and other k values when filling in the character'a'+x. Sum is updated with the change of x.
            }
        }
        for(it=out[i].begin();it!=out[i].end();it++)
        {
            update(1,a[*it].y1,a[*it].y2,1,m,seg[a[*it].kind],-1);
        }
    }
    ll ans=inf;
    rep(i,0,k)
    {
        ll res=p[n][m]-p[a[i].x2][a[i].y2]+p[a[i].x1-1][a[i].y2]+p[a[i].x2][a[i].y1-1]-p[a[i].x1-1][a[i].y1-1];  //First remove the part to be filled in and calculate the difference between the other parts.
        res+=s[a[i].kind][a[i].x2][a[i].y2]-s[a[i].kind][a[i].x1-1][a[i].y2]-s[a[i].kind][a[i].x2][a[i].y1-1]+s[a[i].kind][a[i].x1-1][a[i].y1-1];//Add the difference of this part and
        ans=min(ans,res);
    }
    printf("%lld\n",ans);
    return 0;
}


There's actually a quicker way to do it.

log can actually be removed.  
For each rectangular parameter a,b,c,d, the corresponding characters are marked with + 1 at (a,b), (c+1,d+1), (c+1,b) and (a,d+1). Then we find the prefix sum. It can be found that for the prefix sum of any rectangle, if it is inside the rectangle, it is just + 1, otherwise it is 0. (Draw a picture, you know)
The next step is to enumerate the letters of each location, then two-dimensional prefix sum. Do the same as before

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define mp make_pair
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll inf=0x3fffffffffffff;
const ll mod=1000000007;
const int maxn=1e3+100;
struct node
{
    int x1,y1,x2,y2,kind;
}a[maxn*300];
char map[maxn][maxn];
int cnt[30];
ll p[maxn][maxn],s[30][maxn][maxn];  //Two Binary Prefixes and Sums
int g[30][maxn][maxn];

int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    rep(i,1,n+1) scanf("%s",map[i]+1);
    rep(i,0,k)
    {
        scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
        char str[10];
        scanf("%s",str);
        a[i].kind=str[0]-'a';
        g[a[i].kind][a[i].x1][a[i].y1]++,g[a[i].kind][a[i].x2+1][a[i].y2+1]++;
        g[a[i].kind][a[i].x1][a[i].y2+1]--,g[a[i].kind][a[i].x2+1][a[i].y1]--;
    }
    
    rep(i,1,n+1)
    {
        rep(j,1,m+1)
        {
            int num=0;
            ll sum=0;
            memset(cnt,0,sizeof(cnt));
            rep(x,0,26)
            {
                g[x][i][j]+=g[x][i-1][j]+g[x][i][j-1]-g[x][i-1][j-1];  //Two-dimensional prefix and update
                cnt[x]=g[x][i][j];
                num+=cnt[x];
                sum+=cnt[x]*x;
            }
            cnt[map[i][j]-'a']+=k-num;
            sum+=(map[i][j]-'a')*(k-num);
            rep(x,0,26)
            {
                if(x==map[i][j]-'a')
                    p[i][j]=p[i-1][j]+p[i][j-1]-p[i-1][j-1]+sum; //Sum of the difference values of the other k sub-matrices (1,1)-(i,j) recorded by p[i][j]
                s[x][i][j]=s[x][i-1][j]+s[x][i][j-1]-s[x][i-1][j-1]+sum; //s[x][i][j] denotes the sum of the differences between the sub-matrices (1,1)-(i,j) and the other k after filling in the characters'a'+x
                if(x>0) cnt[x]+=cnt[x-1];
                sum+=cnt[x]-(k-cnt[x]);   //Sum is the sum of the difference between point (i,j) and other k values when filling in the character'a'+x. Sum is updated with the change of x.
            }
        }
    }
    ll ans=inf;
    rep(i,0,k)
    {
        ll res=p[n][m]-p[a[i].x2][a[i].y2]+p[a[i].x1-1][a[i].y2]+p[a[i].x2][a[i].y1-1]-p[a[i].x1-1][a[i].y1-1];  //First remove the part to be filled in and calculate the difference between the other parts.
        res+=s[a[i].kind][a[i].x2][a[i].y2]-s[a[i].kind][a[i].x1-1][a[i].y2]-s[a[i].kind][a[i].x2][a[i].y1-1]+s[a[i].kind][a[i].x1-1][a[i].y1-1];//Add the difference of this part and
        ans=min(ans,res);
    }
    printf("%lld\n",ans);
    return 0;
}

Posted by TheAngst on Sun, 16 Dec 2018 05:33:04 -0800